[SDOI2016]牆上的句子


顯然行,列沒有關系,其實就是給\(n+m\)個串。所以只考慮行。

假設我們知道了所有行的讀法,怎樣求答案?顯然是直接模擬,但是為了接下來的擴展,考慮一個網絡流做法。對於每一種出現過的單詞,正反各建一個點,正點向反點連容量為\(2\)的邊。(這里為了方便默認正着字典序比反着小。)如果它在某個串中是正着讀的,那么\(S\)向正點連容量為\(\inf\)的邊,如果它在某個串中是反着讀的,那么反點向\(T\)連容量為\(\inf\)的邊。那么如果一個單詞正反都出現了,就要割掉中間那條邊,產生\(2\)的代價。

考慮如果某一行的讀法未知怎樣連邊。不知道怎么想的對於每一個出現的單詞,反串向所在的這一行連\(\inf\)邊,這一行向正串連\(\inf\)邊。為什么是對的呢。。。考慮已知的行對未知行的影響,比如一個已知行和未知行都有\(ab\)這個單詞,並且已知行這個單詞的讀法是\(ab\)。那么如果\(ab->ba\)的邊不割,就代表未知行也必須讀成\(ab\),並且\(S\)到這一行就是連通的。如果還有一個限制使得這一未知行必須讀成\(ba\),同理這一行到\(T\)也是連通的,這樣\(S,T\)就連通了,必須找一些邊割掉。而未知行對未知行的影響也是由已知行間接產生的,我覺得很玄學,反正itst說是對的。。。。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
const int inf = 1e9;

int to[N], ww[N], nxt[N], h[N], tt = 1, dep[N], cur[N], nc = 0, s, t, n, m, row[N], col[N];
string str[N];
map<string, int> id;
set<string> pal;

void adde(int u, int v, int w) {
    to[++tt] = v, ww[tt] = w, nxt[tt] = h[u], h[u] = tt;
    to[++tt] = u, ww[tt] = 0, nxt[tt] = h[v], h[v] = tt;
}

bool bfs() {
    memset(dep + 1, 0, nc * 4);
    queue<int> Q;
    Q.push(s);
    dep[s] = 1;
    while(!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for(int i = h[u], v; v = to[i], i; i = nxt[i])
            if(!dep[v] && ww[i]) {
                dep[v] = dep[u] + 1, Q.push(v);
                if(v == t) return 1;
            }
    }
    return 0;
}

int dfs(int u, int flow) {
    if(u == t) return flow;
    int ret = 0;
    for(int &i = cur[u], v; v = to[i], i; i = nxt[i])
        if(dep[v] == dep[u] + 1 && ww[i]) {
            int d = dfs(v, min(flow, ww[i]));
            ww[i] -= d, ww[i ^ 1] += d, ret += d, flow -= d;
            if(!flow) break;
        }
    if(flow) dep[u] = 0;
    return ret;
}

int dinic() {
    int ret = 0;
    while(bfs()) {
        memcpy(cur + 1, h + 1, nc * 4);
        ret += dfs(s, inf);
    }
    return ret;
}

vector<string> split(string s, char c) {
    string now;
    vector<string> ret;
    for(auto x : s) {
        if(x == c) {
            if(!now.empty()) ret.push_back(now);
            now.clear();
        } else now += x;
    }
    if(!now.empty()) ret.push_back(now);
    return ret;
}

string rev(string s) {
    reverse(s.begin(), s.end());
    return s;
}

int cmp(string s) {
    if(s < rev(s)) return 1;
    if(s > rev(s)) return -1;
    return 0;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin >> T;
    while(T--) {
        tt = 1, memset(h, 0, sizeof(h)), id.clear(), pal.clear();
        cin >> n >> m;
        for(int i = 0; i < n; i++) cin >> row[i];
        for(int i = 0; i < m; i++) cin >> col[i];
        for(int i = 0; i < n; i++) cin >> str[i];
        s = n + m + 1, t = nc = s + 1;
        for(int i = 0; i < n; i++) {
            auto v = split(str[i], '_');
            int fl = 0;
            for(auto x : v) fl += cmp(x);
            fl *= row[i];
            for(auto x : v) {
                string a = x, b = rev(x);
                if(a > b) swap(a, b);
                if(a == b) {
                    pal.insert(a);
                    continue;
                }
                if(!id[a]) id[a] = ++nc, id[b] = ++nc, adde(nc - 1, nc, 2);
                if(fl > 0) adde(s, id[a], inf);
                else if(fl < 0) adde(id[b], t, inf);
                else adde(id[b], i + 1, inf), adde(i + 1, id[a], inf);
            }
        }
        for(int i = 0; i < m; i++) {
            string tmp;
            for(int j = 0; j < n; j++) tmp += str[j][i];
            auto v = split(tmp, '_');
            int fl = 0;
            for(auto x : v) fl += cmp(x);
            fl *= col[i];
            for(auto x : v) {
                string a = x, b = rev(x);
                if(a > b) swap(a, b);
                if(a == b) {
                    pal.insert(a);
                    continue;
                }
                if(!id[a]) id[a] = ++nc, id[b] = ++nc, adde(nc - 1, nc, 2);
                if(fl > 0) adde(s, id[a], inf);
                else if(fl < 0) adde(id[b], t, inf);
                else adde(id[b], i + n + 1, inf), adde(i + n + 1, id[a], inf);
            }
        }
        cout << dinic() + pal.size() << '\n';
    }
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM