To_Heart—题解——[HAOI2010]计数
题目
题解
首先我们发现题目要求的就是一个可重复的康拓展开,那么我们考虑它与原本的 不可重的康托展开 本质上就只是 由全排列转换为可重集排列。
但是这道题目不允许我们使用取模,所以说我们需要对可重集排列公式进行转换。
我们考虑可重排列的组合意义,转换为我们把每个元素从小到大排列,每一次往原序列插入最小的元素,然后再把剩下的元素插进那些没有插的空里就好了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
#define db double
char s[1005];
int a[1005];
int n;
ll ans=0;
ll c[1005][1005];
ll Sum[400005];
ll C(ll n,ll m){
if(n<0||m<0) return 0ll;
return c[n][m];
}
void Init(int N){
c[0][0]=1;
for(int i=1;i<=N;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
ll Fuck(ll qwq){
ll now=1;
for(int i=0;i<=9;i++){
now*=C(qwq,Sum[i]);
qwq-=Sum[i];
}
return now;
}
signed main(){
Init(1000);
cin>>(s+1);n=strlen(s+1);
for(int i=1;i<=n;i++) {
a[i]=s[i]-'0';
Sum[a[i]]++;
}
for(int i=1;i<=n;i++){
for(int j=0;j<a[i];j++){
if(!Sum[j]) continue;
Sum[j]--;ans+=Fuck(n-i);Sum[j]++;
}
Sum[a[i]]--;
}
printf("%lld\n",ans);
return 0;
}