显然我们只要知道每个状态合不合法我们就能解决这个问题。
两两枚举相邻的字符, 去找不合法状态。
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} bitset<1 << 17> can[17][17]; char s[N]; int n, p, ans = inf, c[1 << 17]; vector<int> pos[17], vc; vector<int> to[1 << 17]; bool G[17][17]; bool ok[1 << 17]; bool vis[1 << 17]; struct ST { int Log[N], dp[N][20]; void build(char *s, int n) { Log[1] = 0; for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1; for(int i = 1; i <= n; i++) dp[i][0] = 1 << (s[i] - 'a'); for(int j = 1; j <= Log[n]; j++) for(int i = 1; i <= n; i++) dp[i][j] = dp[i][j - 1] | dp[i + (1 << (j - 1))][j - 1]; } inline int query(int L, int R) { if(L > R) return 0; int k = Log[R - L + 1]; return dp[L][k] | dp[R - (1 << k) + 1][k]; } } rmqOr; int main() { scanf("%d%d", &n, &p); scanf("%s", s + 1); for(int i = 0; i < p; i++) for(int j = 0; j < p; j++) scanf("%d", &G[i][j]); for(int i = 0; i < (1 << p); i++) { ok[i] = true; for(int j = 0; j < p; j++) { if(i >> j & 1) continue; to[i].push_back(j); } } rmqOr.build(s, n); for(int i = 1; i <= n; i++) pos[s[i] - 'a'].push_back(i); for(int i = 1; i < (1 << p); i++) for(int j = 0; j < p; j++) if(i >> j & 1) c[i] += SZ(pos[j]); for(int i = 0; i < p; i++) { for(int j = 0; j < p; j++) { if(G[i][j]) continue; if(i == j) { for(int k = 1; k < SZ(pos[i]); k++) can[i][j][rmqOr.query(pos[i][k - 1] + 1, pos[i][k] - 1)] = true; } else { vc.resize(SZ(pos[i]) + SZ(pos[j])); merge(ALL(pos[i]), ALL(pos[j]), vc.begin()); for(int k = 1; k < SZ(vc); k++) { if(s[vc[k]] != s[vc[k - 1]]) { can[i][j][rmqOr.query(vc[k - 1] + 1, vc[k] - 1)] = true; } } } for(int mask = 0; mask < (1 << p); mask++) { if(!can[i][j][mask]) continue; for(auto& k : to[mask]) can[i][j][mask | (1 << k)] = true; } } } for(int mask = 0; mask < (1 << p); mask++) { int fmask = mask ^ ((1 << p) - 1); for(int i = 0; i < p && ok[mask]; i++) { if(mask >> i & 1) { for(int j = i; j < p && ok[mask]; j++) { if(mask >> j & 1) { if(can[i][j][fmask]) ok[mask] = false; } } } } } vis[(1 << p) - 1] = true; queue<int> que; que.push((1 << p) - 1); while(!que.empty()) { int mask = que.front(); que.pop(); chkmin(ans, c[mask]); for(int i = 0; i < p; i++) { if(mask >> i & 1 && !vis[mask ^ (1 << i)] && ok[mask ^ (1 << i)]) { vis[mask ^ (1 << i)] = true; que.push(mask ^ (1 << i)); } } } printf("%d ", ans); return 0; } /* */