zoukankan      html  css  js  c++  java
  • 鲳数 [数位dp]

    鲳数


    color{red}{正解部分}

    从低到高len+1len+1 位的数字为 xx, 考虑 xx 与后面 lenlen 位组成逆序对的贡献,

    先考虑 x=1x=-1 时的贡献, 为 len×10lenlen imes 10^{len}, 其中每个数字出现的次数都相同,
    再考虑 x[0,9]x in [0, 9], 贡献变为 len×10len×x10=len×10len1×xlen imes 10^{len} imes frac{x}{10}=len imes10^{len-1} imes x .

    f[i,j]f[i, j] 表示 x=ix=i 右区间为 [0,j][0, j]ii 与 右区间 构成的贡献, 则 f[i,j]=10ji(j+1)f[i, j] = 10^{j}i(j+1),

    [0,i][0, i] 位 无限制地填数 产生的总逆序对为 g[i]g[i], 则 g[i]=10g[i1]+j=09f[j,i]g[i] = 10g[i-1] + sumlimits_{j=0}^9 f[j, i] .

    设当前位置为 ii, 上界为 limlim, 选择的数字为 xx, ansans 是初值为 00 的变量,
    最高位为 tptp, Tong[p]Tong[p] 表示 从 最高位 到 第 i+1i+1pp 数字出现的次数,
    suf[p]suf[p] 表示从 第 pp 位 到 00 位 的数字转化为十进制后的值,

    现在按位 从低到高 进行处理,

    • x<limx < lim, 总共有 limlim 个符合条件的 xx, 枚举 x[0,lim)x in [0, lim),

      1. [0,i)[0, i) 内部的贡献, lim×g[i1]lim imes g[i-1]
      2. xx[0,i)[0, i) 构成的贡献: f[x,i1]f[x, i-1]
      3. (i,tp](i, tp][0,i)[0, i) 构成的贡献: j=09Tong[j]×f[j,i1]sumlimits_{j=0}^9 Tong[j] imes f[j, i-1]
      4. xx(i,tp](i, tp] 构成的贡献: 10ij=x+19Tong[j]10^i sumlimits_{j=x+1}^9Tong[j]

      所以该情况的总贡献为 lim×g[i1]+x=0lim1(f[x,i1]+j=09Tong[j]×f[j,i1]+10ij=x+19Tong[j])lim imes g[i-1] + sumlimits_{x=0}^{lim-1} left( f[x, i-1] + sumlimits_{j=0}^9 Tong[j] imes f[j, i-1] + 10^isumlimits_{j=x+1}^9Tong[j] ight), 累计进 ansans .

    • x=limx = lim, 考虑计算 xx 与前面原数位产生的逆序对贡献, 贡献为 (suf[i1]+1)×j=lim+19Tong[j](suf[i-1]+1) imessumlimits_{j=lim+1}^9 Tong[j], 累加进 ansans .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    using namespace std;
    #define reg register
    typedef long long ll;
    
    const int maxn = 500005;
    const int mod = 998244353;
    
    int T;
    int len[2];
    int g[maxn];
    int pw[maxn];
    int A[2][maxn];
    int Tong[maxn];
    int f[11][maxn];
    
    char Cmp_1[maxn];
    char Cmp_2[maxn];
    
    void Init(){
            pw[0] = 1; for(reg int i = 1; i < maxn; i ++) pw[i] = 10ll*pw[i-1] % mod;
            for(reg int j = 0; j < maxn; j ++)
                    for(reg int i = 0; i <= 9; i ++) f[i][j] = 1ll*pw[j]*i % mod *(j+1) % mod;
            for(reg int i = 1; i < maxn; i ++){
                    g[i] = 10ll*g[i-1] % mod;
                    for(reg int j = 0; j <= 9; j ++) g[i] = (g[i] + f[j][i-1]) % mod;
            }
    }
    
    int Solve(int fl){
            if(!len[fl]) return 0;
            ll res = 0;
            for(reg int i = 0; i < len[fl]; i ++) Tong[A[fl][i]] ++;
            int suf = 0;
            for(reg int i = 0; i < len[fl]; i ++){
                    int lim = A[fl][i]; Tong[lim] --;
                    if(i){
                            res += 1ll*lim*g[i-1] % mod, res -= res>=mod?mod:0;
                            for(reg int x = 0; x < lim; x ++) res += f[x][i-1], res -= res>=mod?mod:0;
                            for(reg int j = 0; j <= 9; j ++) res += 1ll*lim*Tong[j]%mod*f[j][i-1] % mod, res -= res>=mod?mod:0;
                    }
                    /*
                    for(reg int x = 0; x < lim; x ++) 
                            for(reg int j = x+1; j <= 9; j ++) res += 1ll*pw[i]*Tong[j] % mod, res %= mod;
                    */
                    for(reg int j = 1; j <= 9; j ++) res += (std::min(j-1, lim-1)+1ll)*Tong[j]%mod*pw[i]%mod, res -= res>=mod?mod:0;
                    for(reg int j = lim+1; j <= 9; j ++) res += (1ll*suf + 1) * Tong[j] % mod, res -= res>=mod?mod:0;
                    suf = (suf + (1ll*lim*pw[i]%mod)) % mod; 
            }
            return res;
    }
    
    int main(){
            Init(); int fuck;
            scanf("%d%d", &T, &fuck);
            while(T --){
                    scanf("%s%s", Cmp_1, Cmp_2);
                    len[0] = strlen(Cmp_1), len[1] = strlen(Cmp_2);
                    for(reg int i = 0; i < len[0]; i ++) A[0][i] = Cmp_1[len[0]-i-1] - '0';
                    for(reg int i = 0; i < len[1]; i ++) A[1][i] = Cmp_2[len[1]-i-1] - '0';
                    A[0][0] --; int t  = 0;
                    while(A[0][t] < 0) A[0][t] += 10, A[0][++ t] --;
                    if(!A[0][len[0]-1]) len[0] --;
                    printf("%d
    ", (Solve(1) - Solve(0) + mod) % mod);
            }
            return 0;
    }
    
  • 相关阅读:
    知者不言,言者不知:论华人工程师之领导力
    vscode: Visual Studio Code 常用快捷键
    工作10年的我却没拼过刚毕业的美国女孩,亚裔们到底输在哪儿?
    不要再学习框架了!
    托福100分什么水平
    (转)Eclipse中快速输入System.out.println()的快捷键
    人生不相见,动如参与商
    Amazon onsite behavior question
    Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore
    浅谈volatile与automicInteger
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822435.html
Copyright © 2011-2022 走看看