知识点:LL可以存到20!,m个箱子,m个球,不允许空箱的模型
题意:给定一个数n(n->1e18),问其中每种数字出现至少一次,且不超过总次数,且没有前导零有多少种组合情况
思路:暴力枚举每个数字出现的次数,接下来就是n个箱子,m个球,不允许有空箱子的模型.想题的时候想到这个模型,却不知道怎么做,基础的组合数学... 复杂度cnt[1]*cnt[2]*---- cnt[9]*10
#include<bits/stdc++.h>
#define PI acos(-1.0)
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
const int N=4e5+5;
const int MOD=1e9+7;
ll a[N],sum[N];
ll cnt[50];
ll pro[50];
ll c(int n,int m){//计算组合数
return pro[n]/pro[m]/pro[n-m];
}
ll cul(){
ll n=0;
ll ans=1;
for(int i=0;i<=9;i++) n+=a[i];
for(int i=0;i<=9;i++){//上述放球模型
ans*=c(n,a[i]);
n-=a[i];
}
return ans;
}
inline ll dfs(int num){
if(num==10){
ll res=cul();
// cout <<res << endl;
if(a[0]>0){// 对于存在0的情况.把a[0]情况下的res 减去 第一位是0的情况
a[0]--;
res-=cul();
a[0]++;
}
return res;
}
if(cnt[num]==0){
a[num]=0;
return dfs(num+1);
}
ll ans=0;
for(int i=1;i<=cnt[num];i++){
a[num]=i;
ans+=dfs(num+1);
}
return ans;
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
pro[0]=pro[1]=1;
for(int i=2;i<=20;i++) pro[i]=i*pro[i-1];
ll n;
cin>>n;
while(n){
cnt[n%10]++;
n/=10;
}
cout << dfs(0)<<"\n";
return 0;
}