CodeForces 991 E.Bus数(DFS +順列)

質問の意味:

デジタルの文字列は、数字列構成数字列B、満たす解体する必要が:
(B 3 6 Aが存在すると仮定したら、少なくとも現れオーバー1.A番号は、次にBが有し得る1-3 6ヶ月)。
0をリードせずに2.Bは
どのように多くの異なるBの合計を頼みます

例えば、2028 =指定された文字列A
、次にB溶液は:208、280、802、820、2028、2082、2208、2280、2802、2820、8022、8202、8220、の13種類の合計

アイデア:

先计算出数字串A中每种数字各有多少个。
dfs枚举每种数字使用的个数。
假设当前数字总数为k,那么全排列方案数为ans=k!
因为相同的数字交换位置是同一种,所以要去重:
ans=ans/(a[0]!*a[1]!*a[2]!*a[3]!*a[4]!...*a[9]!),其中a[i]是数字i出现的次数
另外有0的时候还要减掉前导零的情况:
挑出一个0作为前导零,然后计算剩下的数的方案数(步骤和上面一样),减掉即可

コード:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=25;
char s[maxm];
int fac[maxm];
int cnt[maxm];
int a[maxm];
int ans;
void dfs(int x){
    if(x==10){//如果搜到底了
        int tot=0;//总数字个数
        for(int i=0;i<10;i++){
            tot+=a[i];
        }
        int now=fac[tot];//全排列方案数
        for(int i=0;i<10;i++){
            now/=fac[a[i]];//去重
        }
        if(a[0]>=1){//还要排除前导0的情况
            int p=fac[tot-1];//挑出一个0放在开头
            p/=fac[a[0]-1];
            for(int i=1;i<10;i++){//计算剩下的数的方案数
                p/=fac[a[i]];
            }
            now-=p;//减去
        }
        ans+=now;
        return ;
    }
    for(int i=1;i<=cnt[x];i++){//枚举选取的数字个数
        a[x]=i;
        dfs(x+1);
    }
    if(cnt[x]==0)dfs(x+1);
}
signed main(){
    scanf("%s",s+1);
    int n=strlen(s+1);
    for(int i=1;i<=n;i++){//计算数字个数
        cnt[s[i]-'0']++;
    }
    fac[0]=1;
    for(int i=1;i<=n;i++){//预处理阶乘
        fac[i]=fac[i-1]*i;
    }
    dfs(0);
    cout<<ans<<endl;
    return 0;
}

公開された430元の記事 ウォン称賛36 ビュー20000 +

おすすめ

転載: blog.csdn.net/weixin_44178736/article/details/104364456