解题思路
-
将每个数字出现的次数存在一个数组num[]中(与顺序无关)。
-
将出现过的数字i从1到num[i]遍历。(i from 0 to 9)
-
得到要使用的数字次数数组a[]。
-
对于每一种a使用排列组合公式:
 -
ans += 上面那个公式。(每用一次这个公式对应一个a)
排列组合公式注解
- 减号左边表示的是sum个数字全排列并去重。
- 减号右边表示的是从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;
}