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;	
}
posted @ 2018-06-24 21:13  ninding  阅读(498)  评论(0编辑  收藏  举报