zoukankan      html  css  js  c++  java
  • [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() << '
    ';
        }
        return 0;
    }
    
    
  • 相关阅读:
    STP RSTP
    数组与文字处理
    3 算法、控制结构
    2 变量、运算符、位运算
    1
    小程序点击变换,
    小程序授权demo
    小程序获取参数
    小程序是否转发群还是个人(转发功能)
    小程序分享转发功能实现demo
  • 原文地址:https://www.cnblogs.com/gczdajuruo/p/11151957.html
Copyright © 2011-2022 走看看