[Bzoj1072][SCOI2007]排列perm(状压dp)

Posted sainsist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Bzoj1072][SCOI2007]排列perm(状压dp)相关的知识,希望对你有一定的参考价值。

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1072

状压dp,dp[i][j]表示状态为i,对d取余为j的方案数,则有dp[i|(1<<k)][(j*10+a[k])%d]+=dp[i][j],其中k为不在状态i中的数。

同时,因为有重复的数字,所以最后还要除掉重复数字。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 3e5 + 10;
 5 const ll mod = 1e9 + 7;
 6 const ll INF = 1e18;
 7 int dp[1050][1010];
 8 int main() 
 9     int t;
10     scanf("%d", &t);
11     while (t--) 
12         int d;
13         char s[15];
14         int vis[15];
15         int a[15];
16         scanf("%s%d", s, &d);
17         int len = strlen(s);
18         memset(dp, 0, sizeof(dp));
19         memset(vis, 0, sizeof(vis));
20         for (int i = 0; i < len; i++)
21             a[i] = s[i] - 0, vis[a[i]]++;
22         dp[0][0] = 1;
23         for (int i = 0; i < (1 << len); i++) 
24             for (int j = 0; j < d; j++) 
25                 for (int k = 0; k < len; k++) 
26                     if ((i&(1 << k)) == 0)
27                         dp[i | (1 << k)][(j * 10 + a[k]) % d] += dp[i][j];
28                 
29             
30         
31         int ans = dp[(1 << len) - 1][0];
32         for (int i = 0; i <= 9; i++)
33             for (int j = 1; j <= vis[i]; j++)
34                 ans /= j;
35         printf("%d\n", ans);
36     
37     return 0;
38 

 

以上是关于[Bzoj1072][SCOI2007]排列perm(状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1072][SCOI2007]排列perm

BZOJ1072: [SCOI2007]排列perm 状压DP

[BZOJ1072][SCOI2007]排列perm 状压dp

bzoj1072: [SCOI2007]排列perm

bzoj1072: [SCOI2007]排列perm

BZOJ1072: [SCOI2007]排列perm