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

原文地址:https://www.cnblogs.com/Alruddy/p/9071046.html