题目:交错和
链接:http://hihocoder.com/problemset/problem/1033#
题意:对于一个十进制整数x,令a0、a1、a2、...、an是x从高位到低位的数位,定义f(x)=a0-a1+a2-a3+...an,给出L、R、K,x在L到R之间,求所有满足:f(x)=k的x的和。(0 ≤ l ≤ r ≤ 10^18, |k| ≤ 100)
思路:
L与R太大,连预处理的可能性都没有,很明显的数位DP。
令dp[i][j]为精确的(有前导0)i 位,f(x)值为j 的x的和
令dd[i][j]为精确的i 位,f(x)值为j 的x的个数。
dp[1][i] = i (i从0-9)
dd[1][i] = 1(i从0-9)
当i为奇数时,最后一位前的符号位+,所以dp[i][j] = dp[i][j] + dp[i-1][j-u]*10 + u*dd[i-1][j-u] (u从0-9)
dd[i][j]=dd[i][j] + dd[i-1][j-u] (u从0-9)
当i为偶数时,将j-u改成j+u即可
注意这里的dp求的和是有前导0的,比如3位数里098的f值为0-9+8也就是-1,所以dp[3][k]并不是0到1000里f值为k的数的和,因此我们要重新计算一个不含前导0的。
令op[i][j]为i 位,f(x)值为j 的x的和
令pp[i][j]为i 位,f(x)值为j 的x的个数。
递推方法与dp一样,不同的是初始化,特别的令pp[1][0]=0,这样,等会递推出来的就是不包含前导0的,之后,为了方便,我们可以重新定义op[i][j]为前i 位,f(x)值为j 的x的和,pp也一样,进行下前缀和计算就可以了。
解决完以上两步,这个问题便简单很多了,l到r,我们可以先算出0-r的,再减去0-l的,因此问题就转化成x属于0-l,f(x)值为k的x的和了,比如说3256,那么我们可以先算1000里有多少,1000-2000有多少,2000-3000有多少,再算3000-3100里有多少,3100-3200里有多少......1000里的直接就是op[3][k],1000到2000的,我们可以遍历u从0-9,现在就是1-u+?-?=k有多少了,那么?-?的值应该是k-1+u,也就是op[2][k-1+u],同时注意下细节就可以了。具体看代码。
注:值得注意的是dd[0][0]=1,pp[0][0]=1
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 #define Mod 1000000007 5 typedef long long LL; 6 LL dp[20][300]={0}; 7 LL dd[20][300]={0}; 8 LL op[20][300]={0}; 9 LL pp[20][300]={0}; 10 int getPos(int val) 11 { 12 return val+100; 13 } 14 void Init() 15 { 16 dd[0][100]=1; 17 for(int i=0;i<=9;i++) dd[1][getPos(i)]=1,dp[1][getPos(i)]=i; 18 for(int i=2;i<=18;i++) 19 { 20 if(i&1) 21 { 22 for(int j=0;j<10;j++) 23 { 24 for(int k=j;k<=200;k++) 25 { 26 dp[i][k]=(dp[i][k]+dp[i-1][k-j]*10%Mod+j*dd[i-1][k-j]%Mod)%Mod; 27 dd[i][k]=(dd[i][k]+dd[i-1][k-j])%Mod; 28 } 29 } 30 } 31 else 32 { 33 for(int j=0;j<10;j++) 34 { 35 for(int k=0;k<=200-j;k++) 36 { 37 dp[i][k]=(dp[i][k]+dp[i-1][k+j]*10%Mod+j*dd[i-1][k+j]%Mod)%Mod; 38 dd[i][k]=(dd[i][k]+dd[i-1][k+j])%Mod; 39 } 40 } 41 } 42 } 43 44 for(int i=0;i<=9;i++) pp[1][getPos(i)]=1,op[1][getPos(i)]=i; 45 pp[1][getPos(0)]=0; 46 for(int i=2;i<=18;i++) 47 { 48 if(i&1) 49 { 50 for(int j=0;j<10;j++) 51 { 52 for(int k=j;k<=200;k++) 53 { 54 op[i][k]=(op[i][k]+op[i-1][k-j]*10%Mod+j*pp[i-1][k-j]%Mod)%Mod; 55 pp[i][k]=(pp[i][k]+pp[i-1][k-j])%Mod; 56 } 57 } 58 } 59 else 60 { 61 for(int j=0;j<10;j++) 62 { 63 for(int k=0;k<=200-j;k++) 64 { 65 op[i][k]=(op[i][k]+op[i-1][k+j]*10%Mod+j*pp[i-1][k+j]%Mod)%Mod; 66 pp[i][k]=(pp[i][k]+pp[i-1][k+j])%Mod; 67 } 68 } 69 } 70 } 71 pp[0][getPos(0)]=1; 72 for(int i=1;i<=18;i++) 73 { 74 for(int j=0;j<=200;j++) 75 { 76 op[i][j]=(op[i][j]+op[i-1][j])%Mod; 77 pp[i][j]=(pp[i][j]+pp[i-1][j])%Mod; 78 } 79 } 80 } 81 82 LL solve(LL x,LL p) 83 { 84 if(x<0) return 0; 85 LL tmp=x; 86 int bt[20],bo=0; 87 while(x) 88 { 89 bt[bo++]=x%10; 90 x/=10; 91 } 92 LL io=1; 93 for(int i=1;i<bo;i++) 94 io=io*10; 95 LL sum=0,k=0,kk=0; 96 for(int i=bo-1;i>0;i--) 97 { 98 if((bo-i)&1) 99 { 100 for(int j=0;j<bt[i];j++) 101 { 102 if(i==bo-1&&j==0) 103 { 104 sum=(sum+op[i][getPos(p)])%Mod; 105 } 106 else 107 { 108 for(int u=0;u<=9;u++) 109 { 110 sum=(sum+(kk*100%Mod+j*10+u)%Mod*io/10%Mod*dd[i-1][getPos(p+u-j-k)]%Mod+dp[i-1][getPos(p+u-j-k)])%Mod; 111 } 112 } 113 } 114 k+=bt[i]; 115 kk=(kk*10%Mod+bt[i])%Mod; 116 } 117 else 118 { 119 for(int j=0;j<bt[i];j++) 120 { 121 sum=(sum+(kk*10%Mod+j)%Mod*io%Mod*dd[i][getPos(p+j-k)]%Mod+dp[i][getPos(p+j-k)])%Mod; 122 } 123 k-=bt[i]; 124 kk=(kk*10%Mod+bt[i])%Mod; 125 } 126 io/=10; 127 } 128 if(bo&1) 129 { 130 for(int i=0;i<=bt[0];i++) 131 if(p-k==i) 132 { 133 sum=(sum+kk*10%Mod+i)%Mod; 134 } 135 } 136 else 137 { 138 for(int i=0;i<=bt[0];i++) 139 if(k-p==i) sum=(sum+kk*10%Mod+i)%Mod; 140 } 141 return sum; 142 } 143 int main() 144 { 145 Init(); 146 LL l,r,k; 147 cin>>l>>r>>k; 148 cout<<(solve(r,k)-solve(l-1,k)+Mod)%Mod<<endl; 149 return 0; 150 }
AC代码