hdu 4507 吉哥系列故事——恨7不成妻
第一道数位dp的题目,没什么头绪,递归的算法参考了cxlove大神的写法,链接:http://blog.csdn.net/ACM_cxlove?viewmode=contents
不得不说数位dp是个神奇的算法,这个学会以后多校的很多题目应该就可以做了吧,记得有好多类似的题目><
思路:从最高位开始,每次多放一位,假设求12345,如果现在放了2位12***,那么剩下的可以分为2类,120**,121**,122**是没有限制的,后面的两个**可以取00~99,直接用长度为2的模板结果就可以了,这个是用记忆化搜索实现的,而123**则要限制下一位的数字,要继续到下一位再分类,所以如果不用递归的方法来做代码应该会很长。具体的做法如下:
#include<stdio.h> #include<string.h> #define MOD 1000000007 int va[26]; long long Numcnt[20][7][7][2],Numsum[20][7][7][2],Numsum2[20][7][7][2]; long long numcnt,numsum,numsum2;//数字个数,数字和,数字平方和 long long Inv6,fa[20]; long long dfs(int pos,int x,int y,int z,int flag)//当前位,和除7的余数,数除7的余数,是否含有7 { if(!flag&&Numsum2[pos][x][y][z]!=-1) { numcnt=Numcnt[pos][x][y][z]; numsum=Numsum[pos][x][y][z]; return Numsum2[pos][x][y][z]; } if(pos==0) //所有位都放好了 { if(!z&&x&&y)//如果前面没有7并且最后余数都不是0 Numcnt[pos][x][y][z]=0; else Numcnt[pos][x][y][z]=1; Numsum[pos][x][y][z]=Numsum2[pos][x][y][z]=0; numcnt=Numcnt[pos][x][y][z]; numsum=Numsum[pos][x][y][z]; return Numsum2[pos][x][y][z]; } int max=9; if(flag) max=va[pos]; long long numcntnow=0,numsumnow=0,numsum2now=0;//当前位的对应个数 for(int i=0;i<=max;i++) { int tx=(x+i)%7,ty=(y*10+i)%7,tz=((i==7)||z); numsum2=dfs(pos-1,tx,ty,tz,flag&&(i==max)); long long temp=(i*fa[pos-1])%MOD; numcntnow=(numcntnow+numcnt)%MOD; numsumnow=((numsumnow+numsum)%MOD+(numcnt*temp)%MOD)%MOD; numsum2now=((numsum2now+numsum2)%MOD+(2*temp*numsum)%MOD+(((temp*temp)%MOD)*numcnt)%MOD)%MOD; } if(!flag) { Numcnt[pos][x][y][z]=numcntnow; Numsum[pos][x][y][z]=numsumnow; Numsum2[pos][x][y][z]=numsum2now; } numcnt=numcntnow; numsum=numsumnow; return numsum2now; } long long sum(long long n) { long long x=(n%MOD*((n+1)%MOD))%MOD; x=x*((2*n+1)%MOD)%MOD; return x*Inv6%MOD; } long long cal(long long n) { int lenth=1; while(n) { va[lenth++]=n%10; n/=10; } return dfs(lenth-1,0,0,0,1); } int main() { int T; long long st,end; Inv6=166666668; fa[0]=1; for(int i=1;i<=19;i++) { fa[i]=(fa[i-1]*10)%MOD; } memset(Numsum2,-1,sizeof(Numsum2)); scanf("%d",&T); while(T--) { scanf("%I64d%I64d",&st,&end); long long ans=(sum(end)-sum(st-1))%MOD; ans=((ans-cal(end))%MOD+cal(st-1))%MOD; ans=(ans+MOD)%MOD; printf("%I64d\n",ans); } return 0; }
数位dp练习题:
1.fzu 2113 Jason的特殊爱好
http://acm.fzu.edu.cn/problem.php?pid=2113
2.hdu 2089 不要62
http://acm.hdu.edu.cn/showproblem.php?pid=2089
3.hdu 3555 Bomb
http://acm.hdu.edu.cn/showproblem.php?pid=3555
4.hdu 3652 B-number
http://acm.hdu.edu.cn/showproblem.php?pid=3652
5.hdu 3943 K-th Nya Number
http://acm.hdu.edu.cn/showproblem.php?pid=3943
6.hdu 3709 Balanced Number
http://acm.hdu.edu.cn/showproblem.php?pid=3709
7.hdu 3271 SNIBB
http://acm.hdu.edu.cn/showproblem.php?pid=3271
8.hdu 1336 Word Index
http://acm.hdu.edu.cn/showproblem.php?pid=1336
9.hdu 3967 Zero's Number
http://acm.hdu.edu.cn/showproblem.php?pid=3967
10.hdu 3565 Bi-peak Number
http://acm.hdu.edu.cn/showproblem.php?pid=3565