#组合计数,全排列#洛谷 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);
}
posted @ 2020-06-03 20:54  lemondinosaur  阅读(150)  评论(0编辑  收藏  举报