hdu4507 数位dp~last(求一个区间内所有与7无关数的平方和)
因为这道题目开始学的数位dp,在bestcode那道数位dp(http://www.cnblogs.com/xiao-xin/articles/4168112.html)解决之后,这道题目也终于解决啦!
求一个区间内满足:1.每位都没有7 2.该数每位和不是7倍数 3.该数不是7倍数,这样的数的平方和。
很显然,我们dfs套的是 pos,sum,x,flag,limit 分别表示位,该数%7,该数各位和%7,前面有没有出现7,有没有到达上限
但是对于我们要求的所有符合要求的平方和我们该如何返回?
返回三个参数 符合要求个数,符合要求的数的和,符合要求的数的平方和;我们用一个结构体保存,为什么是三个参数:
(thingking所求平方和递推关系)
另外,本题不用求反面,求反面反而要用逆元,直接求就好啦!
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define LL long long 5 #define MOD 1000000007 6 using namespace std; 7 struct dian{ 8 LL num,sum1,sum2; 9 }dp[25][10][10][2]; 10 LL vis[25][10][10][2]; 11 LL f[25],num[20]; 12 dian dfs(LL pos,LL sum,LL x,LL flag,LL limit) 13 { 14 LL i,tmp,temp; 15 dian n1,n2; 16 if (pos==0) 17 { 18 n1.sum1=n1.sum2=0; 19 n1.num=1; 20 if (sum==0||x==0||flag) n1.num=0; 21 return n1; 22 } 23 if (!limit&&vis[pos][sum][x][flag]!=-1) 24 return dp[pos][sum][x][flag]; 25 tmp=limit?num[pos]:9; 26 n1.num=n1.sum1=n1.sum2=0; 27 for (i=0;i<=tmp;i++) 28 { 29 n2=dfs(pos-1,(sum*10+i)%7,(x+i)%7,flag||i==7,limit&&i==tmp); 30 n1.num=(n1.num+n2.num)%MOD; 31 n1.sum1=(n1.sum1+n2.sum1+((f[pos-1]*i)%MOD*n2.num)%MOD)%MOD; 32 temp=i*f[pos-1]%MOD; 33 n1.sum2=(n1.sum2+(temp*temp%MOD)*n2.num%MOD+ 34 temp*n2.sum1%MOD*2+n2.sum2)%MOD; 35 } 36 if (!limit) 37 { 38 vis[pos][sum][x][flag]=1; 39 dp[pos][sum][x][flag]=n1; 40 } 41 return n1; 42 } 43 int main() 44 { 45 int T; 46 dian n1,n2; 47 LL i,l,r,cnt,temp1,temp; 48 f[0]=1; 49 for (i=1;i<=19;i++) 50 f[i]=(f[i-1]*10)%MOD; 51 scanf("%d",&T); 52 while (T--) 53 { 54 scanf("%I64d%I64d",&l,&r); 55 n1.sum2=n2.sum2=0; 56 memset(vis,-1,sizeof(vis)); 57 cnt=0; 58 while (r>0) 59 { 60 num[++cnt]=r%10; 61 r/=10; 62 } 63 if (cnt>0) n1=dfs(cnt,0,0,0,1); 64 cnt=0; l--; 65 while (l>0) 66 { 67 num[++cnt]=l%10; 68 l/=10; 69 } 70 if (cnt>0) n2=dfs(cnt,0,0,0,1); 71 temp=((n1.sum2-n2.sum2)%MOD+MOD)%MOD; 72 printf("%I64d\n",temp); 73 } 74 return 0; 75 }