[bzoj1072][SCOI2007]排列(状态压缩DP)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1072

分析:看了题解才知道,状态的设计很巧妙,用余数表示,即f[i][j]表示二进制状态i下余数为j的方案数,然后列一列式子就可以了,注意排除相同数字的情况。

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<string>
 5 using namespace std;
 6 const int maxn=1024;
 7 int f[maxn+50][1000];
 8 char s[15];
 9 int t,d;
10 int main()
11 {
12     scanf("%d
",&t);
13     while(t)
14     {
15         --t;
16         scanf("%s%d
",s,&d);
17         int n=strlen(s);
18         memset(f,0,sizeof(f));
19         int m=(1<<n) - 1;
20         for(int i=0;i<n;++i) f[1<<i][(s[i]-48)%d]=1;
21         for(int i=1;i<=m;++i)
22             for(int j=0;j<n;++j)
23                 if((i&(1<<j))!= 0 && i-(1<<j)>=0)
24                     for(int k=0;k<d;++k)
25                         f[i][(10*k+(s[j]-48))%d]+=f[i-(1<<j)][k];
26         for(int i=0;i<=9;++i)
27         {
28             int ans=0;
29             for(int j=0;j<n;++j)
30                 if(s[j]-48==i) ++ans;
31             int c=1;
32             for(int j=2;j<=ans;++j) c*=j;
33             f[m][0]/=c;
34         }
35         printf("%d
",f[m][0]);
36     }
37     return 0;
38 }
View Code
原文地址:https://www.cnblogs.com/wmrv587/p/3970851.html