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;
}
posted @ 2021-11-06 07:36  lahlah  阅读(52)  评论(0编辑  收藏  举报