Codeforces 1117F Crisp String

Crisp String

显然我们只要知道每个状态合不合法我们就能解决这个问题。

两两枚举相邻的字符, 去找不合法状态。

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

/*
*/
原文地址:https://www.cnblogs.com/CJLHY/p/10938441.html