2020杭电多校(三) X Number(数位dp)

时间:2020-08-01
本文章向大家介绍2020杭电多校(三) X Number(数位dp),主要包括2020杭电多校(三) X Number(数位dp)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

这题如果普通数位dp,状态不好表示,但是我们发现,一旦当dp过程中,脱离了被最高项束缚的状态后,后面的数字就可以随便填

因此我们直接用组合数dp计算,首先维护前面出现的数字的个数,之后枚举答案d出现的合法状态的次数

设计dp[][],表示前i位,不包括d,在剩余的个数中已经存了j的答案。因此我们可以枚举i后再枚举k吗,计算这个位选k次的答案。

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
using namespace std;
typedef long long ll;
typedef pair<int,ll> pll;
const int N=5e4+10;
int c[1000][1000];
int s[N];
int d;
int len;
ll dp[25][25];
int cnt[N];
ll l,r;
ll dfs(int pos,int limit,int lead){
    if(pos==-1){
        int mx=0,num=0;
        rep(i,0,9)  if(cnt[i]>cnt[mx]) mx=i;
        rep(i,0,9) if(cnt[i]==cnt[mx]) num++;
        return mx==d&&num==1;
    }
    if(!limit&&!lead){
        ll ans=0;
        int mx=cnt[d];
        rep(i,0,9) if(i!=d) mx=max(mx,cnt[i]+1);
        for(int num=mx;num<=cnt[d]+pos+1;num++){
            memset(dp,0,sizeof(dp));
            dp[0][0]=1;
            rep(i,1,10){
                if(i==d+1){
                    for(int j=0;j<=20;j++) dp[i][j]=dp[i-1][j];
                    continue;
                }
                for(int j=0;j<=cnt[d]+pos+1-num;j++){
                    for(int k=0;k<=num-cnt[i-1]-1&&j-k>=0;k++){
                        dp[i][j]+=dp[i-1][j-k]*c[pos+1-j+k][k];
                    }
                }
            }
            ans+=dp[10][cnt[d]+pos+1-num];
        }
        return ans;
    }
    int up=limit?s[pos]:9;
    ll ans=0;
    for(int i=0;i<=up;i++){
        if(!lead||i!=0) cnt[i]++;
        ans+=dfs(pos-1,limit&&i==s[pos],lead&&i==0);
        if(!lead||i!=0) cnt[i]--;
    }
    return ans;
}
void init(){
    int i,j;
    c[0][0]=1;
    for(i=1;i<=20;i++){
        c[i][0]=1;
        for(j=1;j<=i;j++){
            c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
}
ll solve(ll x){
    int len=0;
    if(x==0){
        s[0]=0;
        len=1;
    }
    while(x){
        s[len++]=x%10;
        x/=10;
    }
    return dfs(len-1,1,1);
}
int main(){
    ios::sync_with_stdio(false);
    init();
    int t;
    cin>>t;
    while(t--){
        cin>>l>>r>>d;
        cout<<solve(r)-solve(l-1)<<endl;
    }
}
View Code

原文地址:https://www.cnblogs.com/ctyakwf/p/13416873.html