数位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));
	}
} 

  

posted @ 2018-06-05 22:01  诚信肥宅  阅读(167)  评论(1编辑  收藏  举报