#组合计数,全排列#洛谷 2518 [HAOI2010]计数
题目
你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。
比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。
现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0)
分析
类似于数位dp的方法
假设前\(i\)位都处理完了
那么答案就是后面的数字全排列的结果
重复元素的全排列相信很清楚,但是也不可能用高精度
那么可以用组合数代替,那么就是\(\prod c(n-s_i,a_i)\)
代码
#include <cstdio>
#include <cstring>
#define rr register
using namespace std;
typedef long long lll;
lll ans,c[51][51]; char s[51]; int len,cnt[10];
inline lll dp(int now){
rr lll ans=1;
for (rr int i=0;i<10;++i) if (cnt[i])
ans*=c[now][cnt[i]],now-=cnt[i];
return ans;
}
signed main(){
c[0][0]=1;
for (rr int i=1;i<51;++i){
c[i][0]=c[i][i]=1;
for (rr int j=1;j<i;++j)
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
scanf("%s",s+1),len=strlen(s+1);
for (rr int i=1;i<=len;++i) ++cnt[s[i]^48];
for (rr int i=1;i<=len;++i){
for (rr int j=0;j<(s[i]^48);++j)
if (cnt[j]) --cnt[j],ans+=dp(len-i),++cnt[j];
--cnt[s[i]^48];
}
return !printf("%lld",ans);
}