51Nod1230 幸运数

1230 幸运数 

题目来源: HackerRank

基准时间限制:1 秒

空间限制:131072 KB

分值: 320 

难度:7级算法题

        如果一个数各个数位上的数字之和是质数,并且各个数位上的数字的平方和也是质数,则称它为幸运数。
例如:120是幸运数,因为120的数字之和为3,平方和为5,均为质数,所以120是一个幸运数字。
给定x,y,求x,y之间( 包含x,y,即闭区间[x,y])有多少个幸运数。
 

Input

第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行2个数,X, Y中间用空格分割。(1 <= X <= Y <= 10^18)

Output

输出共T行,对应区间中幸运数的数量。

Input示例

2
1 20
120 130

Output示例

4
1

解析:

一看就是打表数位dp啊。。。

考虑到各个位上数字之和及数字的平方和不大,就先把范围内所有质数筛出来。

然后就是数位dp的套路了。

详见代码。

我还是太弱了不知道说啥。。。

 
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll long long
 8 int t;
 9 ll x,y;
10 ll f[20][200][1500];
11 int prime[1500],tot;
12 bool notprime[1500];
13 int a[20];
14 void get_prime(){
15     notprime[0]=true;
16     notprime[1]=true;
17     for (int i=2;i<=1499;++i){
18         if (!notprime[i]) prime[++tot]=i;
19         for (int j=1;j<=tot&&i*prime[j]<=1499;++j){
20             notprime[i*prime[j]]=true;
21             if (i%prime[j]==0) break;
22         } 
23     }
24 }
25 ll dfs(int pos,int limit,int sum,int squ){
26     if (pos<=0) return ((!notprime[sum])&&(!notprime[squ]));
27     if (!limit&&f[pos][sum][squ]!=-1) return f[pos][sum][squ];
28     int lim=limit?a[pos]:9;
29     ll res=0;
30     for (int i=0;i<=lim;++i){
31         res+=dfs(pos-1,limit&&(i==lim),sum+i,squ+i*i);
32     }
33     if (!limit) f[pos][sum][squ]=res;
34     return res;
35 }
36 ll solve(ll xx){
37     int len=0;
38     while (xx){
39         a[++len]=xx%10;
40         xx/=10;
41     }
42     return dfs(len,1,0,0);
43 }
44 int main(){
45     memset(f,-1,sizeof(f));
46     get_prime();
47     scanf("%d",&t);
48     while (t--){
49         scanf("%lld%lld",&x,&y);
50         printf("%lld\n",solve(y)-solve(x-1));
51     }
52     return 0;
53 }
View Code

 

posted @ 2018-01-13 09:40  lonlyn  阅读(269)  评论(0编辑  收藏  举报