数位dp 51nod1230
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1230
感觉这道7级题有点略简单,是我的错觉吗?
题意不再复述,由于只有18位数字,所以数位和的上限为162,平方和的上限为1458
所以我们可以认为只有18*162*1458种状态,这是可以存下来的
写记忆化搜索时设四个参数,一个当前位,一个算数位和,一个平方和,一个最大值限制
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stack> #include<map> #include<vector> #include<queue> #include<set> #include<iomanip> #include<cctype> #include<stack> using namespace std; const int MAXN=2e3+5; const int INF=1<<30; const long long mod=1e9+7; const double eps=1e-8; #define ll long long #define edl putchar('\n') #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define FOR(i,a,b) for(int i=a;i<=b;i++) #define ROF(i,a,b) for(int i=a;i>=b;i--) #define FORLL(i,a,b) for(ll i=a;i<=b;i++) #define ROFLL(i,a,b) for(ll i=a;i>=b;i--) #define mst(a) memset(a,0,sizeof(a)) #define mstn(a,n) memset(a,n,sizeof(a)) #define zero(x)(((x)>0?(x):-(x))<eps) int a[25],s[MAXN+50]; ll dp[25][165][1465]; void prime() { ll su[2000],cnt; cnt=0; FOR(i,2,MAXN) s[i]=1; s[0]=s[1]=0; for(ll i=2;i<=MAXN;i++) { if(s[i]) { su[++cnt]=i; for(ll j=2;su[cnt]*j<MAXN;j++) { s[su[cnt]*j]=0; } } } } ll dfs(int pos,int s1,int s2,int limit) { if(pos==0) { return s[s1]&&s[s2]; } if(!limit&&dp[pos][s1][s2]!=-1) return dp[pos][s1][s2]; int up=limit?a[pos]:9; ll ans=0; FOR(i,0,up) ans+=dfs(pos-1,s1+i,s2+i*i,limit&&i==a[pos]); if(!limit) dp[pos][s1][s2]=ans; return ans; } ll solve(ll x) { int cnt=0; while(x) { a[++cnt]=x%10; x/=10; } a[cnt+1]=0; return dfs(cnt,0,0,1); } int main() { int cnt=1; prime(); FOR(i,0,18) FOR(j,0,162) FOR(k,0,1458) dp[i][j][k]=-1; ll T,n,m; cin>>T; while(T--) { /*cin>>n>>m; cout<<solve(m)-solve(n-1)<<endl;*/ scanf("%lld%lld",&n,&m); printf("%lld\n",solve(m)-solve(n-1)); } }