1 条题解

  • 0
    @ 2025-8-24 21:56:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar guyan
    **

    搬运于2025-08-24 21:56:14,当前版本为作者最后更新于2020-03-01 11:28:19,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目大意

    给出 n+mn+m 个字符串 , 每个字符串包含若干单词 , 可以正着读也可以反着读 , 有些字符串已经确定了阅读方法 , 要求确定剩下字符串的阅读方法 , 使得正反串都出现的单词数最少.

    保证对于同一个字符串内的单词 , 要么所有单词的正串字典序大于等于反串 , 要么所有单词的反串字典序大于等于正串.

    solution

    回文串一定产生 11 的贡献 , 单独处理

    看到正反可以联想到 文理分科 , 类比这道题考虑最小割做法

    一开始是想着直接将 n+mn+m 个字符串作为被分的对象 , 然而并建不了图 , 因为对于单词来说这是存在性问题

    转换思维 查阅题解 , 将单词作为被划分集合的对象

    设源点为 ss , 汇点为 tt , 划分的两个集合为 SSTT

    将一个单词分为正串与反串两个节点 ( 这里正串定义为正反串中字典序较小的串 ) , 正串向反串连容量为 22 的边

    正串被划分到 SS 集合 \rightarrow 正串出现

    正串被划分到 TT 集合 \rightarrow 正串没有出现

    反串被划分到 TT 集合 \rightarrow 反串出现

    反串被划分到 SS 集合 \rightarrow 反串没有出现

    当正串一定出现时 , ss 向正串连容量为 INFINF 的边

    当反串一定出现时 , 反串向 tt 连容量为 INFINF 的边

    接下来考虑那些没有确定读法的字符串

    这里有一个重要条件

    对于同一个字符串内的单词 , 要么所有单词的正串字典序大于等于反串 , 要么所有单词的反串字典序大于等于正串.

    意味着一个字符串中所有出现的单词都是正串 , 或者是反串 ( 这里假设都是正串 )

    设使得字符串中单词都是正串的读法是将字符串划入 SS 集合

    字符串被划入 SS 集合 \rightarrow 正串出现

    字符串被划入 TT 集合 \rightarrow 反串出现

    若字符串被划入 SS 集合 , 其中出现的正串也一定在 SS 集合 , 于是字符串向每个其中出现的单词的正串连 INFINF

    若字符串被划入 TT 集合 , 其中出现的反串也一定在 TT 集合 , 于是字符串中出现单词的反串向字符串连 INFINF

    code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 7e2 + 5;
    const int M = N * N;
    const int INF = 0x3f3f3f3f;
    int _w;
    
    int head[N] , eidx , dep[N] , que[N] , he , ta , cur[N] , st , ed;
    struct Edge { int nxt , to , flow , cap; } edge[M];
    
    void addedge( int u , int v , int cap ) { 
      edge[++eidx] = (Edge) { head[u] , v , 0 , cap }; head[u] = eidx;
      edge[++eidx] = (Edge) { head[v] , u , 0 , 0 }; head[v] = eidx;
    }
    
    bool bfs( void ) {
      static int u;
      memset( dep , 0 , sizeof dep );
      dep[que[he = ta = 1] = st] = 1;
      while( he <= ta ) {
        u = que[he++];
        for( int i = head[u] , v ; ~i ; i = edge[i].nxt )
          if( !dep[v = edge[i].to] && edge[i].cap > edge[i].flow )
            dep[que[++ta] = v] = dep[u] + 1;
      }
      return dep[ed] != 0;
    } 
    
    int dfs( int u , int fl ) {
      if( u == ed || !fl ) return fl;
      int g = 0 , d;
      for( int & i = cur[u] ; ~i ; i = edge[i].nxt ) 
        if( dep[edge[i].to] == dep[u] + 1 && ( d = dfs( edge[i].to , min( edge[i].cap - edge[i].flow , fl - g ) ) ) ) {
          edge[i].flow += d , edge[i ^ 1].flow -= d;
          if( ( g += d ) >= fl ) break;
        }
      return g;
    }
    
    int dinic( void ) {
      int res = 0;
      while( bfs() ) {
        memcpy( cur , head , sizeof head );
        res += dfs( st , INF );
      }
      return res;
    }
    
    int n , m , col[N] , row[N] , idx;
    char str[N][N];
    set<string> pal;
    map<string,int> id;
    
    void analyze( string s , int type , int u ) {
      static int n; 
      static string a , b;
      n = s.length();
      for( int i = 0 , r , flag ; i < n ; i = r + 1 ) {
        r = i;
        if( s[i] == '_' ) continue;
        while( r < n - 1 && s[r + 1] != '_' ) ++r;
        a = s.substr( i , r - i + 1 );
        b = a; reverse( b.begin() , b.end() );
        if( b < a ) swap( a , b ) , flag = -1;
        else flag = 1;
        if( a == b ) {
          pal.insert( a );
          continue;
        }
        if( !id.count( a ) ) {
          id[a] = ++idx;
          id[b] = ++idx;
          addedge( idx - 1 , idx , 2 );
        } flag *= type;
        if( flag == 1 ) addedge( st , id[a] , INF );
        else if( flag == -1 ) addedge( id[b] , ed , INF );
        else addedge( id[b] , u , INF ) , addedge( u , id[a] , INF );
      }
    }
    
    void solve( void ) {
      _w = scanf("%d%d",&n,&m); idx = n + m;
      memset( head , -1 , sizeof head ) , eidx = -1;
      id.clear() , pal.clear();
      for( int i = 1 ; i <= n ; ++i ) _w = scanf("%d",row + i );
      for( int i = 1 ; i <= m ; ++i ) _w = scanf("%d",col + i );
      for( int i = 1 ; i <= n ; ++i ) _w = scanf("%s",str[i]+1);
      st = 0 , ed = N - 1;
      static string tmp;
      for( int i = 1 ; i <= n ; ++i ) {
        tmp = str[i] + 1;
        analyze( tmp , row[i] , i );
      }
      for( int i = 1 ; i <= m ; ++i ) {
        tmp = "";
        for( int j = 1 ; j <= n ; ++j )
          tmp += str[j][i];
        analyze( tmp , col[i] , i + n );
      }
      printf("%d\n",dinic() + int( pal.size() ) );
    }
    
    int main( void ) {
      int T;
      _w = scanf("%d",&T);
      while( T-- ) solve();
      return 0;
    }
    
    • 1

    信息

    ID
    3002
    时间
    1000ms
    内存
    125MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者