CF908G New Year and Original Order
https://www.luogu.com.cn/problem/CF908G
好题!!!
显然可以每一位来考虑,再乘上
1
0
k
10^k
10k,但是这样仍然不是很好做
我们考虑一个经典的套路,差分
把
j
j
j的贡献变为
≥
j
\ge j
≥j的个数,那么
j
j
j恰好会被贡献
j
j
j 次
然后我们在吧
1
,
2
,
3
,
.
.
.
,
9
1, 2,3,...,9
1,2,3,...,9分别带进去
设
f
[
i
]
[
j
]
[
0
/
1
]
f[i][j][0/1]
f[i][j][0/1]表示考虑了前
i
i
i位,有
j
j
j个位置
≥
X
\ge X
≥X,是否卡上界
转移不难,计算贡献哪里只用考虑那 j j j个排序后一定是排在最后的,贡献形如 111..11 111..11 111..11的形式即可
code:
#include<bits/stdc++.h>
#define ll long long
#define N 705
#define mod 1000000007
using namespace std;
char a[N];
int f[N][N][2], pw[N], n;
int calc(int x) {
memset(f, 0, sizeof f);
for(int i = 0; i <= a[1]; i ++) f[1][i >= x][i == a[1]] ++;
for(int i = 1; i < n; i ++)
for(int j = 0; j <= i; j ++)
for(int lim = 0; lim <= 1; lim ++) if(f[i][j][lim]) {
for(int k = 0; k <= (lim? a[i + 1] : 9); k ++) {
(f[i + 1][j + (k >= x)][lim & (k == a[i + 1])] += f[i][j][lim]) %= mod;
// printf("%d %d %d -> %d %d %d %d\n", i, j, lim, i + 1, j + (k >= x), lim & (k == a[i + 1]), f[i][j][lim]);
}
}
ll ret = 0;
for(int i = 1; i <= n; i ++) ret = ret + 1ll * pw[i] * (f[n][i][0] + f[n][i][1]) % mod, ret %= mod;
// printf("%lld ", ret);
return ret;
}
int main() {
scanf("%s", a + 1);
n = strlen(a + 1);
for(int i = 1; i <= n; i ++) a[i] -= '0', pw[i] = (pw[i - 1] * 10ll + 1) % mod;
int ans = 0;
for(int i = 1; i <= 9; i ++) ans = (ans + calc(i)) % mod;
printf("%d", ans);
return 0;
}