[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 }