LightOJ 1021 状态压缩DP
给定一个基底base和一个数k,再给一串互不相同的字符,要求字符的全排列base进制数中,能被k整除的个数。
mask表示每一个字符所在的位置被选中的状态位
i表示mask状态下,能被k取余运算后余数的值
c表示当前考虑加入最后的字符位置
s[c]表示字符代表数字
b(c) = 1<<c
得状态转移方程:
dp[mask|b(c)][(i*base+s[c])%k] += dp[mask][i]
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <ctype.h>
using namespace std;
typedef long long LL;
const LL N = 1 << 16 | 1;
const int M = 20;
LL dp[N][M];
int cnt[N],lb[M];
vector<int> G[M];
int t, m, k;
string ss;
inline int sss(int j) {
return isdigit(ss[j])? (ss[j]-'0') : (ss[j]-'A'+10);
}
void init() {
lb[0] = 1;
for(int i = 1; i < M; i++) {
lb[i] = lb[i-1] * 2;
}
cnt[0] = 0;
for(int i = 1; i < N; i++) {
cnt[i] = cnt[i&(i-1)] + 1;
}
}
void solve() {
int n = ss.size();
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;
for(int i = 0; i < M; i++) {
G[i].clear();
}
for(int i = 0; i < (1<<n); i++) {
G[cnt[i]].push_back(i);
}
for(int i = 0; i < n; i++) {
for(int c = 0; c < G[i].size(); c++) {
int s = G[i][c];
for(int j = 0; j < n; j++) {
if(!(s&lb[j])) {
for(int x = 0; x < k; x++)
dp[s|lb[j]][(x*m+sss(j))%k] += dp[s][x];
}
}
}
}
static int kase = 0;
cout << "Case " << ++kase << ": ";
cout << dp[(1<<n)-1][0] << endl;
}
int main() {
init();
freopen("in.txt", "r", stdin);
cin >> t;
while (t--) {
cin >> m >> k;
cin >> ss;
solve();
}
return 0;
}
如果有错误,请指出,谢谢