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 }