[HAOI2010]计数

数位DP逐位确定的思想

因为我们要求小于当前数的个数,位数不即它的,可以认为有前导零

所以可以枚举每一位(给定数的位数),再枚举当前位填什么,

当填的数小于给定数的这一位时,后面可以直接用组合数,因为填什么,怎么填都符合要求(小于给定数),就是剩下的数集中还没有被填的数都要做组合数(这个求法很妙???)

当填的数等于给定数的这一位时,此时值为一,不能计算,要推下去(就是下面再小于等于都是基于这一位等于来的)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #include<map>
 9 #include<vector>
10 #include<stack>
11 using namespace std;
12 typedef long long ll;
13 const int maxn=57;
14 ll ans,n;
15 ll a[maxn],cnt[maxn],C[maxn][maxn];
16 char s[maxn];
17 ll get(int n){
18   ll ret=1;
19   for(int i=0;i<=9;i++){
20     if(cnt[i]){
21       ret*=C[n][cnt[i]];
22       n-=cnt[i];
23     }
24   }
25   return ret;
26 }
27 int main(){
28   scanf("%s",s+1);n=strlen(s+1);
29   for(int i=1;i<=n;i++){
30     a[i]=s[i]-'0';cnt[a[i]]++;
31   }
32   C[0][0]=1;
33   for(int i=0;i<=51;i++){
34     for(int j=0;j<=51;j++){
35       C[i+1][j]+=C[i][j];C[i+1][j+1]+=C[i][j];
36     }
37   }
38   for(int i=1;i<=n;i++){
39     for(int j=0;j<a[i];j++){
40       if(cnt[j]){
41         cnt[j]--;ans+=get(n-i);cnt[j]++;
42       }
43     }
44     cnt[a[i]]--;
45   }
46   cout<<ans<<endl;
47 }

 

转载于:https://www.cnblogs.com/lcan/p/9927317.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值