hihoCoder1033 交错和 数位DP
Posted hchlqlz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder1033 交错和 数位DP相关的知识,希望对你有一定的参考价值。
题目:交错和
链接: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 }
以上是关于hihoCoder1033 交错和 数位DP的主要内容,如果未能解决你的问题,请参考以下文章