zoukankan      html  css  js  c++  java
  • 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
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    或得最新的采购单号并改变为定长
    javaScript学习之路(1)词法结构
    如何让IE下载时下载内容自动跳转到迅雷等下载软件中
    简单的数据库查询操作
    1.1软件工程概述之软件危机
    SQL基础(巧记范式)
    给程序员的五点建议--如何成为编程高手并以此创业
    License控制解决方案
    MVC+三层+ASP.NET简单登录验证
    我曾七次鄙视自己的灵魂
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13416873.html
Copyright © 2011-2022 走看看