lightoj 1158 - Anagram Division 状压DP

来源:互联网 发布:汉武帝与唐太宗 知乎 编辑:程序博客网 时间:2024/05/29 16:56

给定一个数字串s和数字d,问有多少种不同的排列是d的倍数..

开始想直接DP,但是考虑到可能无法去重

所以状压DP,每次找到一个没有取的数字,加上去...

然后根据前面lightoj1060学的康拓逆展开...

重复元素再除一下阶乘OK过样例提交TLE..

优化了一个地方时间缩短一半。

#include<bits/stdc++.h>using namespace std;#define ll long long#define mod 1000007#define inf 0x3f3f3f3fint dp[(1<<11)+10][1002];char s[12];int num[12],f[12];int main(){    int t;    scanf("%d",&t);    f[0]=1;    for(int i=1;i<=10;i++) f[i]=f[i-1]*i;    for(int cas=1;cas<=t;cas++)    {        int d,n;        scanf("%s %d",s,&d);        memset(num,0,sizeof(num));        n=strlen(s);        for(int i=0;i<n;i++)        {            num[s[i]-'0']++;            s[i]=s[i]-'0';        }        memset(dp,0,sizeof(dp));        dp[0][0]=1;        for(int i=0;i<(1<<n);i++)        {            for(int j=0;j<n;j++)            {                if(i&(1<<j)) continue;                for(int k=0;k<d;k++)                {                    if(dp[i][k]==0) continue;//优化                    dp[i|(1<<j)][(k*10+s[j])%d]+=dp[i][k];                }            }        }        int ans=dp[(1<<n)-1][0];        for(int i=0;i<10;i++)        {            ans=ans/f[num[i]];        }        printf("Case %d: %d\n",cas,ans);    }    return 0;}


0 0