CF 1073E Segment Sum

CF 1073E Segment Sum

题意:求[L,R]中,不同数位不超过k个数的和。

题解:很简单的数位dp,dp [i] [j] 表示第i位前面的数字中,前导0之外不同数位的状态为j的数字个数和它们的和(用个pair来存)。然后正常数位dp就行了,特殊处理一下前导0(加状态比较好处理)。

#include <bits/stdc++.h>

#define fi first
#define se second
#define MP make_pair

using namespace std;

typedef long long LL;

const int N = 25;
const int M = 1<<10;
const int MOD = 998244353;

typedef pair<int,int> PII;

PII f[N][M+5][2][2];

LL l, r, k;

int st[N], tol;

LL num[M+5], v[N];

PII dfs(int dep, int state, int flag, int head){
    if(dep==0){
        if(num[state]<=k)return MP(0,1);
        else return MP(0,0);
    }

    if(~f[dep][state][flag][head].fi)return f[dep][state][flag][head];

    PII& res=f[dep][state][flag][head];

    res.fi=res.se=0;

    int up=flag?st[dep]:9;
    for(int i=0;i<=up;++i){
        int t;
        if(head&&i==0){
            t=state;
        }else{
            t=state|(1<<i);
        }
        PII p=dfs(dep-1,t,flag&&i==up,head&&i==0);
        res.se+=p.se;
        res.se%=MOD;
        res.fi+=(1ll*v[dep]*i%MOD*p.se%MOD+p.fi)%MOD;
        res.fi%=MOD;
    }

    return res;
}

LL cal(LL x){
    memset(f,-1,sizeof f);
    tol=0;

    while(x>0){
        st[++tol]=x%10;
        x/=10;
    }

    return dfs(tol, 0, 1, 1).fi;
}

int main(){
    cin>>l>>r>>k;
    num[1]=1;
    for(int i=2;i<=M;++i)num[i]=num[i>>1]+(i&1);
    v[1]=1;
    for(int i=2;i<=19;++i)v[i]=v[i-1]*10ll%MOD;

    int ra=cal(r), la=cal(l-1);

    int ans=(ra-la)%MOD;

    if(ans<0)ans+=MOD;

    cout<<ans;

    return 0;
}
原文地址:https://www.cnblogs.com/JohnRan/p/13809831.html