51nod 1230:幸运数

51nod 1230:幸运数

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1230

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

数位DP

代码如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn=22;
 6 int dig[maxn],prime[1459]={0},num_prime=0,T;
 7 ll f[maxn][163][1459],x,y;
 8 bool p[1459]={1,1};
 9 ll dfs(int pos,int sum,int sqrsum,int limit){
10     if (pos<0) return (!p[sum])&&(!p[sqrsum]);
11     if (!limit&&f[pos][sum][sqrsum]!=-1) return f[pos][sum][sqrsum];
12     ll res=0;
13     int last=limit?dig[pos]:9;
14     for (int i=0;i<=last;i++){
15         res+=dfs(pos-1,sum+i,sqrsum+i*i,limit&&(i==last));
16     }
17     if (!limit) f[pos][sum][sqrsum]=res;
18     return res;
19 }
20 ll solve(ll n){
21     int len=0;
22     while (n){
23         dig[len++]=n%10;
24         n/=10;
25     }
26     return dfs(len-1,0,0,1);
27 }
28 void init(){
29     memset(f,-1,sizeof(f));
30     for(long i=2;i<1459;i++){
31         if(!p[i])prime[num_prime++]=i;
32         for(long j=0;j<num_prime&&i*prime[j]<1459;j++){
33             p[i*prime[j]]=1;
34             if(!(i%prime[j]))break;
35         }
36     }
37 }
38 int main(void){
39     init();
40     scanf("%d",&T);
41     while(T--){
42         scanf("%lld%lld",&x,&y);
43         printf("%lld\n",solve(y)-solve(x-1));
44     }
45 }

 

posted @ 2017-04-18 00:11  barriery  阅读(397)  评论(0编辑  收藏  举报