bzoj 4667: 小y的密码

来源:互联网 发布:mysql 修改表结构语句 编辑:程序博客网 时间:2024/06/03 15:24

不错的题啊 然而我太菜了orz

想一想 不难发现其实从小到大搜索哪几个数并不会超时
然后就算一下就好了。。。

至于怎么算
就枚举哪个位开始低于n的对应位 剩下的位随便填就用组合数算
如果位数比n少直接算就好了 首位不为0即可

#include<bits/stdc++.h>using namespace std;typedef long long LL;inline int read(){    char ch=getchar(); int x=0,f=1;    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}    return x*f;}int n,k,m,a[11],al,ans,c[11],tot,jc[11];LL d[11];bool check(){    if(!tot || !c[tot])return 0;    LL s=0; int u=c[(tot+1)>>1];    for(int i=1;i<=tot;++i)    {        int g=c[i]-u; LL o= g>=0?d[g]:d[-g];        if(g<0) s+= k&1?-o:o;        else s+=o;    }    if(s>m)return 0;    return 1;}int num[11];void add(int x){    LL s=jc[x];    for(int i=0;i<=9;++i)s/=jc[num[i]];    ans+=s;}void cal(){    for(int i=0;i<=9;++i) num[i]=0;    for(int i=1;i<=tot;++i) num[c[i]]++;    if(tot<al){        for(int j=9;j>0;--j)            if(num[j]>0){                num[j]--;                add(tot-1);                num[j]++;            }        return;    }    for(int i=tot;i>=1;--i){        int o= i==tot?0:-1;        for(int j=a[i]-1;j>o;--j)            if(num[j]>0){                num[j]--;                add(i-1);                num[j]++;            }        if(!num[a[i]])break;        num[a[i]]--; if(i==1)ans++;    }}void dfs(int x){    if(check())cal();    if(tot==al)return;    ++tot;    for(int i=x;i<=9;++i)        c[tot]=i,dfs(i);    --tot;}int main(){    n=read(),k=read(),m=read();    while(n) a[++al]=n%10,n/=10;    jc[0]=1; for(int i=1;i<=al;++i)jc[i]=jc[i-1]*i;    for(int i=0;i<=9;++i){        d[i]=1;        for(int j=1;j<=k;++j)d[i]*=i;    }    dfs(0);    printf("%d\n",ans);    return 0;}