2425: [HAOI2010]计数

来源:互联网 发布:mac 编译安装php5.6 编辑:程序博客网 时间:2024/06/15 07:10

题目链接

题目大意:给你一个最多50位的数,求在所有通过由他去掉0和重新排列数字顺序能产生的数中,比他小的有多少个

题解:构成的数是原数的排列(包含前导0)

09num[]

dpiix,
1.i0x1ni便
2.ixnum[x],

我的收获:计数,按位,质因数分解处理阶乘

#include <cstdio>#include <algorithm>#include <cstring>#include <iostream>#include <cmath>using namespace std;typedef long long ll;const int M=55;const int p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};int n,num[10],mi[25];ll ans;char s[M];void change(int x,int k){    for(int i=1;x!=1;i++){        while(!(x%p[i])) x/=p[i],mi[i]+=k;    }}void fac(int x,int f){    for(int i=1;i<=x;i++)        change(i,f);}ll calc(int x){    memset(mi,0,sizeof(mi));    fac(x,1);    for(int i=0;i<=9;i++) fac(num[i],-1);    ll ret=1;    for(int i=1;i<=15;i++) ret*=pow(p[i],mi[i]);    return ret;}void work(){    for(int i=1;i<=n;i++){        for(int j=0;j<s[i]-'0';j++)            if(num[j]) num[j]--,ans+=calc(n-i),num[j]++;//这里要加回来,因为并不是固定的决策        num[s[i]-'0']--;    }    printf("%lld\n", ans);}void init(){    scanf("%s",s+1);n=strlen(s+1);    for(int i=1;i<=n;i++) ++num[s[i]-'0'];}int main(){    init();    work();    return 0;}