BZOJ2425:[HAOI2010]计数——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=2425

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

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

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

题意看了半天终于看懂了。

我们从高位到低位枚举比当前位小的数,然后对于剩下的元素放在后面全排列即可。

可重元素全排列=元素个数!/每个元素个数!的乘积。

防止爆ll可以将分子分母分解后约分再计算。

(貌似本质上是一道很暴力有点思维的水题,不是数位dp)

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=51;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
char s[N];
int n,sum,t[11],p[N];
ll ans=0;
int main(){
    cin>>s+1;
    n=strlen(s+1);
    for(int i=1;i<=n;i++)t[s[i]-'0']++,sum++;
    for(int i=1;i<=n;i++){
    for(int j=0;j<s[i]-'0';j++){
        if(t[j]){
        memset(p,0,sizeof(p));
        t[j]--;sum--;
        for(int k=0;k<=9;k++)
            for(int l=2;l<=t[k];l++)
            p[l]++;
        ll tmp=1;
        for(int k=2;k<=sum;k++){
            tmp*=k;
            for(int l=2;l<N;l++){
            while(p[l]&&tmp%l==0){
                p[l]--;tmp/=l;
            }
            }
        }
        ans+=tmp;
        t[j]++;sum++;
        }
    }
    t[s[i]-'0']--,sum--;
    }
    printf("%lld\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-04-29 09:26  luyouqi233  阅读(229)  评论(0编辑  收藏  举报