Codeforces 991E. Bus Number (DFS+排列组合)

解题思路

  1. 将每个数字出现的次数存在一个数组num[]中(与顺序无关)。
  2. 将出现过的数字i从1到num[i]遍历。(i from 0 to 9)
  3. 得到要使用的数字次数数组a[]。
  4. 对于每一种a使用排列组合公式:

  5. ans += 上面那个公式。(每用一次这个公式对应一个a)

排列组合公式注解

  1. 减号左边表示的是sum个数字全排列并去重。
  2. 减号右边表示的是从a[0]中选出一个0当做第一个数字,并对其他数字全排列并去重。

抱歉,写的可能比较混乱,还有部分细节需要读者处理。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

string s;
int num[10];
ll jc[20];//阶乘 
int tempNum[10];
ll ans = 0;

void dfs(int x){
    //如果0~9都填充好了数字 
    if(x == 10){
        //cnt表示所有数字的个数 
        int cnt = 0;
        for(int i = 0;i < 10; ++i){
            cnt += tempNum[i];
        }
        //排列组合公式 开始 
        ll p = jc[cnt];
        for(int i = 0;i < 10; ++i){
            p /= jc[tempNum[i]];
        }
        if(tempNum[0] >= 1)
            p -= (p*tempNum[0]/cnt);
        //排列组合公式 结束 
        ans += p;
        return ;
    }
    //对于出现过的数字,个数从1开始 
    for(int i = 1;i <= num[x]; ++i){
        tempNum[x] = i;
        dfs(x+1);
    }
    if(num[x] == 0){
        dfs(x+1);
    }
}


int main(){
    ios::sync_with_stdio(false);
    cin >> s;
    for(auto i:s) num[i-'0']++;
    //算阶乘 
    jc[0] = 1;
    for(ll i = 1;i <= 19; ++i){
        jc[i] = jc[i-1]*i;
    }
    dfs(0);
    cout << ans << endl;
    return 0;   
}

猜你喜欢

转载自www.cnblogs.com/zhangjiuding/p/9221765.html