鲳数 [数位dp]

鲳 数 鲳数


正 解 部 分 \color{red}{正解部分}

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

先考虑 x = − 1 x=-1 x=1 时的贡献, 为 l e n × 1 0 l e n len \times 10^{len} len×10len, 其中每个数字出现的次数都相同,
再考虑 x ∈ [ 0 , 9 ] x \in [0, 9] x[0,9], 贡献变为 l e n × 1 0 l e n × x 10 = l e n × 1 0 l e n − 1 × x len \times 10^{len} \times \frac{x}{10}=len\times10^{len-1}\times x len×10len×10x=len×10len1×x .

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

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

设当前位置为 i i i, 上界为 l i m lim lim, 选择的数字为 x x x, a n s ans ans 是初值为 0 0 0 的变量,
最高位为 t p tp tp, T o n g [ p ] Tong[p] Tong[p] 表示 从 最高位 到 第 i + 1 i+1 i+1 p p p 数字出现的次数,
s u f [ p ] suf[p] suf[p] 表示从 第 p p p 位 到 0 0 0 位 的数字转化为十进制后的值,

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

  • x < l i m x < lim x<lim, 总共有 l i m lim lim 个符合条件的 x x x, 枚举 x ∈ [ 0 , l i m ) x \in [0, lim) x[0,lim),

    1. [ 0 , i ) [0, i) [0,i) 内部的贡献, l i m × g [ i − 1 ] lim \times g[i-1] lim×g[i1]
    2. x x x [ 0 , i ) [0, i) [0,i) 构成的贡献: f [ x , i − 1 ] f[x, i-1] f[x,i1]
    3. ( i , t p ] (i, tp] (i,tp] [ 0 , i ) [0, i) [0,i) 构成的贡献: ∑ j = 0 9 T o n g [ j ] × f [ j , i − 1 ] \sum\limits_{j=0}^9 Tong[j] \times f[j, i-1] j=09Tong[j]×f[j,i1]
    4. x x x ( i , t p ] (i, tp] (i,tp] 构成的贡献: 1 0 i ∑ j = x + 1 9 T o n g [ j ] 10^i \sum\limits_{j=x+1}^9Tong[j] 10ij=x+19Tong[j]

    所以该情况的总贡献为 l i m × g [ i − 1 ] + ∑ x = 0 l i m − 1 ( f [ x , i − 1 ] + ∑ j = 0 9 T o n g [ j ] × f [ j , i − 1 ] + 1 0 i ∑ j = x + 1 9 T o n g [ j ] ) lim\times g[i-1] + \sum\limits_{x=0}^{lim-1} \left( f[x, i-1] + \sum\limits_{j=0}^9 Tong[j] \times f[j, i-1] + 10^i\sum\limits_{j=x+1}^9Tong[j]\right) lim×g[i1]+x=0lim1(f[x,i1]+j=09Tong[j]×f[j,i1]+10ij=x+19Tong[j]), 累计进 a n s ans ans .

  • x = l i m x = lim x=lim, 考虑计算 x x x 与前面原数位产生的逆序对贡献, 贡献为 ( s u f [ i − 1 ] + 1 ) × ∑ j = l i m + 1 9 T o n g [ j ] (suf[i-1]+1)\times\sum\limits_{j=lim+1}^9 Tong[j] (suf[i1]+1)×j=lim+19Tong[j], 累加进 a n s ans ans .


实 现 部 分 \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\n", (Solve(1) - Solve(0) + mod) % mod);
        }
        return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值