HDU 4507 数位DP

来源:互联网 发布:泰克网络实验室怎么样 编辑:程序博客网 时间:2024/05/29 16:17

题意

问某个区间内与7无关的数的平方和%1e9+7的结果是多少。
与7无关即:不含7,可以被7整除,所有位加起来可以被7整除

题解

这道题不是一般的数位DP题,一般的数位DP题都是统计某个区间内有多少个这样的数。这种数位DP就很简单了,直接DFS记忆话搜索,过滤一些情况,就可以了。
这道题过滤情况没有什么难度,难点在于要求的是平方和,以及最后极其变态的MOD要求。
因为要求平方和,所以就必须要想办法重构平方和。平方和=(i*10^(len)+x)^2。(此处将一个数拆分为两部分,进行平方和)进行分解后,可以得到2*i*10^(len)*x*cnt(cnt为能够组成这个数的可能情况)+(i*10^(len))^2+sum(x)。由上述式子可以看出,还需要两个变量,sum(x)和cnt。
cnt就很简单了,就是一个区间内符合与7无关的数的个数。
至于sum(x)依然是分解成两部分进行求解,sum(x)=(i*10^(len)+x)。后面的x就是转移到这个状态之前的sum(x),这样的话sum(x)很容就能求得。

注意事项

这道题的难点一方面在于信息的记录与转移,另一方面就在于变态的数据范围。由于数据范围很大,随时可能超LongLong,因此需要及时MOD。

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define INF 0x3f3f3f3f#define LL long long#define MAXN 100010#define EPS 1e-10#define MOD 1000000007#define int LLusing namespace std;struct Node{    int cnt,sum,sqsum;    Node(){};    Node(int c,int s,int q):cnt(c),sum(s),sqsum(q){}};int dig[20];Node dp[20][10][10];int c[20];Node dfs(int len,int sum,int mod,bool up){    if(len==0){        if(mod!=0&&sum!=0)            return Node(1,0,0);        else            return Node(0,0,0);    }    if(!up&&dp[len][sum][mod].cnt!=-1)        return dp[len][sum][mod];    int n=up?dig[len]:9;    Node ans=Node(0,0,0);    UP(i,0,n+1){        if(i!=7){            Node nd=dfs(len-1,(sum+i)%7,(mod*10+i)%7,up&&(i==n));            ans.cnt=(ans.cnt+nd.cnt)%MOD;            ans.sum=(ans.sum+nd.sum+((c[len-1]*nd.cnt)%MOD*i))%MOD;            ans.sqsum=(ans.sqsum+nd.sqsum+((2*nd.sum*i)%MOD*c[len-1])%MOD+(((nd.cnt*i)%MOD*c[len-1])%MOD*i*c[len-1])%MOD)%MOD;        }    }    if(!up){        dp[len][sum][mod]=ans;    }    return ans;}Node solve(int x){    int len=0;    W(x>0){        dig[++len]=x%10;        x/=10;    }    return dfs(len,0,0,true);}void init(){    c[0]=1;    UP(i,1,20){        c[i]=(c[i-1]*10)%MOD;    }}main(){    int kase;    scanf("%I64d",&kase);    init();    MEM(dp,-1);    W(kase--){        int a,b;        scanf("%I64d%I64d",&a,&b);        printf("%I64d\n",(solve(b).sqsum+MOD-solve(a-1).sqsum)%MOD);    }}
原创粉丝点击