zoukankan      html  css  js  c++  java
  • CF_884_F(NetFlow)

    codeforces_884_f


    题目大意:给出一串长为n的字符串(保证n为偶数),定义反回文串为每一个位置的对应位置上的字母都不等于它(for each i : s[i] != s[n+1-i]),现可将原字符串随意排列,得到一个反回文串(保证有解),若最后的反回文串(设为s')上的某一位置is[i] == s'[i],则可以得到一个美丽值b[i],求将原串变为反回文串所可以得到的最大美丽值和(sum_b[i]s[i] == s'[i])。

    题解:直接求最大美丽值有困难,可以反着想,我们通过改动某些位置让原串变为反回文串,若可以求出最小花费之和(对应位置的美丽值),用总的美丽值之和扣除最小花费便是答案。打的时候由于E题加粗内存限制,题面都没看就来了F,发现F是费用流还有点开心,结果画了好久都没有画出来建图,最后看了题解好一会才想通建图方式。
    建图解释:首先这题的图有5层,1(S)->2( 26 letters )->3( 26 * n/2 nodes )->4( n poisions )->T,其实最关键的就是第三层,因为其他层都是正常操作,基本上都会这样建图,关键就是第三层的26*n/2个点是用来做什么的?接下来给出解释:首先,我们目标是用最小费用最大流跑出最小花费(即达到最大流量的最小花费)。那么显然(2->5)这些层的容量都是1,因为每个字母对于每个位置,以及每个位置对于整串只能贡献1流量,然后(1->2)的边容量为每个字母在s串中出现的次数,也很好理解,就是最多能用几次,而费用我们选择在第三四层计算,所以剩下的费用都是0。
    关键来了,第三层是什么东西,第三层可以这样理解,对于某一个字母(称作cur),显然cur如果在第一个位置,就不能在最后一个位置(因为要反回文),所以我们将cur在第三层中的第一个点和第一个和最后一个位置(第4层)建边(f=1,w=?),先考虑为何不拿将cur分出n个在第三层的点,分别与对应位置建边?因为反回文,如果第1条和第n条的花费是这n条中最小的两个,那么都会被采用,那么第一个位置和最后一个位置都是同一个字母,就违反了反回文的性质,所以只拆出n/2个点,那么费用是多少?回顾一下我们要做的事情,是构造出一个反回文,而如果流量从cur第一个属于第三层的点流到第一个位置,说明cur填在第一个位置,那么如果原来第一个位置就是cur显然可以得到b[1],那么因为我们最后是用总美丽值减去我们跑出来的最小费用,所以这条边的费用为0,这样被扣掉就拿到了b[1],反之如果原来第一个位置不是cur,这条边的费用就是b[1],这样被扣掉就拿不到了,对于其他位置以此类推(某个点第三层的第2个点,连向第四层中n个位置的第2个位置和倒数第2个位置,即每个字母在第三层中的n/2个点,分别对应第一倒一,第二倒二,第三倒三……)。

    PS:依旧是Dij + g[],我的g就是势数组。


    #pragma comment(linkerr, "/STACK: 1024000000,1024000000")
    #include <bits/stdc++.h>
    #define pb push_back
    #define mp make_pair
    #define eb emplace_back
    #define em emplace
    #define pii pair<int,int>
    #define de(x) cout << #x << " = " << x << endl
    #define clr(a,b) memset(a,b,sizeof(a))
    #define INF (0x3f3f3f3f)
    #define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
    #define F first
    #define S second
    using namespace std;
    
    const int N = 110;
    int n, S, T;
    int ct[27], b[N];
    char s[N];
    struct Edge
    {
    	int v, nxt;
    	int f, w;
    };
    Edge e[N*N<<2];
    int h[N*N], ect;
    int dis[N*N], g[N*N], pv[N*N], pe[N*N];
    
    bool vis[N*N];
    void init()
    {
    	clr(h,-1);
    	ect = 0;
    }
    void _add( int u, int v, int f, int w )
    {
    	e[ect].v = v; e[ect].f = f; e[ect].w = w; e[ect].nxt = h[u]; h[u] = ect++;
    	e[ect].v = u; e[ect].f = 0; e[ect].w =-w; e[ect].nxt = h[v]; h[v] = ect++;
    }
    
    pii mfmc( int s, int t )
    {
    	int mxf = 0, mnc = 0;
    	while ( 1 )
    	{
    		clr(vis,0); clr(dis,INF);
    		dis[s] = 0;
    		priority_queue<pii> q;
    		q.push( {0,s} );
    		while ( !q.empty() )
    		{
    			pii nw = q.top(); q.pop();
    			int u = nw.S;
    			if ( vis[u] ) continue;
    			vis[u] = 1;
    			for ( int i = h[u], v = e[i].v; i+1; i = e[i].nxt, v = e[i].v )
    			{
    				int c = e[i].w + g[u] - g[v];
    				if ( e[i].f > 0 && dis[v] > dis[u] + c )
    				{
    					dis[v] = dis[u] + c;
    					q.push( {-dis[v],v} );
    					pv[v] = u; pe[v] = i;
    				}
    			}
    		}
    		if ( dis[t] == INF ) break;
    		for ( int i = s; i <= t; i ++ )
    			g[i] += dis[i];
    		int d = INF;
    		for ( int i = t; i != s; i = pv[i] )
    			d = min( d, e[pe[i]].f );
    		for ( int i = t; i != s; i = pv[i] )
    			e[pe[i]].f -= d, e[pe[i]^1].f += d;
    		mxf += d; mnc += d*g[t];
    	}
    	return {mxf, mnc};
    }
    
    int main()
    {
    	init();
    	int sm = 0;
    	scanf("%d", &n);
    	scanf("%s", s+1);
    	for ( int i = 1; i <= n; i ++ )
    		ct[s[i]-'a'+1] ++;
    	for ( int i = 1; i <= n; i ++ )
    		scanf("%d", &b[i]), sm += b[i];
    		
    	S = 0, T = 26 + 26*n/2 + n + 1;
    	
    	for ( int i = 1; i < 27; i ++ )
    		_add( S, i, ct[i], 0 );
    	
    	int nw, tp;
    	nw = 26;
    	for ( int i = 1; i < 27; i ++ )
    		for ( int j = 1; j+j <= n; j ++ )
    			_add( i, ++nw, 1, 0 );
    			
    	nw = 26 + 26*n/2, tp = 26;
    	for ( int i = 0; i < 26; i ++ )
    		for ( int j = 1; j+j <= n; j ++ )
    			_add( ++tp, nw + j, 1, s[j] - 'a' == i ? 0 : b[j] ),
    			_add( tp, nw + n + 1 - j, 1, s[n+1-j] - 'a' == i ? 0 : b[n+1-j] );
    			
    	nw = T - 1;
    	for ( int i = 0; i < n; i ++ )
    		_add( nw, T, 1, 0 ), nw --;
    		
    	pii cur = mfmc( S, T );
    	printf("%d
    ", sm - cur.S);
    	return 0;
    }
    
  • 相关阅读:
    管道/重定向/环境变量
    用户和组命令
    常用命令
    系统监控及进程
    Centos硬件信息
    Centos系统信息及日志
    linux防火墙
    ipt_connlimit限制并发,ipt_recent限制单位时间内的请求数目
    apache添加mod_limitipconn限制单个ip并发连接数
    php核心技术与最佳实践知识点(下)
  • 原文地址:https://www.cnblogs.com/FormerAutumn/p/10399083.html
Copyright © 2011-2022 走看看