[HAOI2010]计数

题目描述

你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。

现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0).

输入输出格式

输入格式:
只有1行,为1个整数n.

输出格式:
只有整数,表示N之前出现的数的个数。

https://www.luogu.org/problemnew/show/P2518

思路

对于一个数,把其中的0删掉,相当于把0放到了前面。
所以这个问题就是让我们求一下给我们的数的全排列比当前小的有几个。

假如现在有m个位置,我们先把0放法放好,C(m,a[0]);

之后就只有m-a[0]个位置,然后在放1,C(m-a[0],a[1])……

所以答案是 C(m,a[0]) * C(m-a[0],a[1]) * … * C(m-a[0]-a[1]-..-a[8],a[9]);

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long CC[77*2][77*2];
long long C(long long n,long long m)
{
    if(CC[n][m])return CC[n][m];
    if(m==1)return n;
    if(m==0||m==n)return 1;
    if(m>n)return 0;
    CC[n][m]=C(n-1,m)+C(n-1,m-1);
    return CC[n][m];
}
int a[11],v[77];
long long ans;
int n;
char s[77];
long long cfb()
{
    long long ans=1;
    int m=n;
    for(int i=0; i<=9; i++) if(a[i]) ans*=C(m,a[i]),m-=a[i];
    return ans;
}
int main()
{
    scanf("%s",s);
    n=strlen(s);
    for(int i=0; i<n; i++) v[i+1]=s[i]-48,a[v[i+1]]++;
    int l=n;
    for(int i=1; i<=l; i++)
    {
        n--;
        for(int j=0; j<v[i]; j++)
        if(a[j])
        {
            a[j]--; 
            ans+=cfb(); 
            a[j]++;
        }
        a[v[i]]--;
    }
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值