LightOJ1158 Anagram Division(状压DP)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOJ1158 Anagram Division(状压DP)相关的知识,希望对你有一定的参考价值。

题目问一个数字字符串的不重复全排列有几个能被d整除。

  • dp[S][m]表示用字符集合S构成的%d为m的数字字符串个数
  • dp[0][0]=0
  • 我为人人转移,dp[S+{x}][(m*10+str[x]-‘0‘)%d]+=dp[S][m](x∉S)

最后的结果再除以各字符出现次数的阶乘就是答案了,即dp[2strlen-1][0]/(t[0]!*t[1]!*t[2]!*t[3]!*t[4]!*t[5]!*t[6]!*t[7]!*t[8]!*t[9]!)。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 int d[1<<10][1111],fact[11]={1};
 5 int main(){
 6     for(int i=1; i<11; ++i) fact[i]=fact[i-1]*i;
 7     int t,m;
 8     char str[1111];
 9     scanf("%d",&t);
10     for(int cse=1; cse<=t; ++cse){
11         scanf("%s%d",str,&m);
12         int n=strlen(str);
13         memset(d,0,sizeof(d));
14         d[0][0]=1;
15         for(int i=0; i<(1<<n)-1; ++i){
16             for(int j=0; j<m; ++j){
17                 if(d[i][j]==0) continue;
18                 for(int k=0; k<n; ++k){
19                     if((i>>k)&1) continue;
20                     d[i|(1<<k)][(j*10+str[k]-0)%m]+=d[i][j];
21                 }
22             }
23         }
24         int times[10]={0};
25         for(int i=0; i<n; ++i) ++times[str[i]-0];
26         for(int i=0; i<10; ++i){
27             d[(1<<n)-1][0]/=fact[times[i]];
28         }
29         printf("Case %d: %d\n",cse,d[(1<<n)-1][0]);
30     }
31     return 0;
32 }

 

以上是关于LightOJ1158 Anagram Division(状压DP)的主要内容,如果未能解决你的问题,请参考以下文章

1158: 零起点学算法65——进制转换

Employment Planning[HDU1158]

1158 全是1的最大子矩阵

51nod 1158 全是1的最大子矩阵

oracle12c不能进入到http://localhost:1158/em的解决办法

洛谷P1158 导弹拦截 排序