CF908G解题报告
题意
定义\(S(n)\)为将\(n\)的每一位数字升序排序后的值,例如:
\[S(1)=1,S(5)=5,S(50394)=S(3459),S(353535)=333555
\]
计算\(\sum_{i=1}^XS(i)\ mod\ 10^9+7\)。
题解
考虑每一位的贡献可以表示成\(c(digit)=\sum10^i\)的形式,那么通过更改求和顺序我们可以得到:\(Ans=\sum_{digit=1}^9digit*c(digit)=\sum_{digit=1}^9\sum_{i=digit}^9c(i)\)。
考虑枚举\(digit\)如何计算\(\sum_{i=digit}^9c(i)\),它的意义是每个数中不小于\(digit\)的数位有多少个。
那么我们可以得到如下数位\(dp\):
\[\begin{align}
状态设计:&f[i][j][0/1]表示前i位中有j位的值大于等于枚举的dig,前i位小于(0)/等于(1)给定数的前i位\\
init:&f[0][0][1]=1\\
tran:&f[i][j][0]=\sum_{0\leq d\leq9}f[i-1][j-(d\geq dig)][0]+\sum_{0\leq d< s[i]}f[i-1][j-(d>=dig)][0]\\
&f[i][j][1]=f[i-1][j-(s[i]\geq dig)][1]\\
Ans:&\sum_{1\leq i\leq n}f[n][i][0]
\end{align}
\]
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 750, mod = 1e9 + 7;
int n, f[N][N][2], ans, pw[N];
char s[N];
void upd(int &x, int v) {(x += v) >= mod ? x -= mod : 0;}
int calc(int dig) {
memset(f, 0, sizeof(f));
f[0][0][1] = 1;
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= n; j++) {
if(j - (s[i] >= dig) >= 0) f[i][j][1] = f[i - 1][j - (s[i] >= dig)][1];
for(int d = 0; d <= 9; d++) if(j - (d >= dig) >= 0) upd(f[i][j][0], f[i - 1][j - (d >= dig)][0]);
for(int d = 0; d < s[i]; d++) if(j - (d >= dig) >= 0) upd(f[i][j][0], f[i - 1][j - (d >= dig)][1]);
// printf("dig:%d f[%d,%d,0]=%d f[%d,%d,1]=%d\n", dig, i, j, f[i][j][0], i, j, f[i][j][1]);
}
}
int ret = 0;
for(int i = 1; i <= n; i++) upd(ret, 1ll * f[n][i][0] * pw[i] % mod);
// printf("%d\n", ret);
return ret;
}
int main() {
scanf("%s", s + 1); n = strlen(s + 1);
for(int i = 1; i <= n; i++) pw[i] = (1ll * pw[i - 1] * 10 + 1) % mod;
for(int i = n; i >= 1; i--) if(s[i] == '9') s[i] = '0'; else {s[i]++; break;}
for(int i = 1; i <= n; i++) s[i] -= '0';
for(int dig = 1; dig <= 9; dig++) upd(ans, calc(dig));
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号