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;
}
posted @ 2020-04-05 12:44  jhdonghj  阅读(89)  评论(0)    收藏  举报