BZOJ 1072: [SCOI2007]排列perm
状态压缩Dp
f[i][j],i为状态,j为余数
i可以用二进制数表示状态
这样的话状态转移就很简单了
但最后要用排列组合算一下重复排序。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 using namespace std; 6 int i,j,k,n,m,t,a,b,c,d; 7 int p[11]={}; 8 int l[11]={}; 9 int f[1024][1001]={}; 10 bool r[1024][1001]={}; 11 bool e[11]={}; 12 char s; 13 void er(int x) 14 { 15 int i,j,k; 16 k=-1; 17 while(x!=0) 18 { 19 k++; 20 e[k]=x%2; 21 x=x/2; 22 } 23 } 24 int pow(int x,int y) 25 { 26 int i,j; 27 j=1; 28 for(i=1;i<=y;i++) 29 { 30 j=j*x; 31 } 32 return j; 33 } 34 int aa(int x) 35 { 36 int i,j,a,b,c; 37 c=1; 38 for(i=1;i<=x;i++) 39 { 40 c=c*i; 41 } 42 return c; 43 } 44 int main() 45 { 46 scanf("%d",&t); 47 for(n=1;n<=t;n++) 48 { 49 memset(p,0,sizeof(p)); 50 memset(l,0,sizeof(l)); 51 memset(f,0,sizeof(f)); 52 memset(r,0,sizeof(r)); 53 memset(e,0,sizeof(e)); 54 cin>>s; 55 c=-1; 56 while(int(s)!=32) 57 { 58 p[int(s)-48]++; 59 c++; 60 l[c]=int(s)-48; 61 scanf("%c",&s); 62 } 63 scanf("%d",&d); 64 r[0][0]=1; 65 f[0][0]=1; 66 for(i=0;i<=1023;i++) 67 { 68 memset(e,0,sizeof(e)); 69 er(i); 70 a=0; 71 for(j=0;j<=c;j++) 72 { 73 if(e[j]==0) 74 { 75 a=1; 76 } 77 } 78 if(a==0) 79 { 80 a=i; 81 break; 82 } 83 for(j=0;j<=d-1;j++) 84 { 85 if(r[i][j]==1) 86 { 87 for(k=0;k<=c;k++) 88 { 89 if(e[k]==0) 90 { 91 f[i+pow(2,k)][(j*10+l[k])%d]+=f[i][j]; 92 r[i+pow(2,k)][(j*10+l[k])%d]=1; 93 } 94 } 95 } 96 } 97 } 98 for(i=0;i<=9;i++) 99 { 100 f[a][0]=f[a][0]/aa(p[i]); 101 } 102 cout<<f[a][0]<<endl; 103 } 104 return 0; 105 }