zoukankan      html  css  js  c++  java
  • AGC030E Less than 3

    AGC030E [* hard]

    给的两个长度为 (n)01(s,t),串的连续段长度不超过 (2),每次可以将 (s) 的一个位置反转,要求操作后连续段长度仍然不超过 (2),求使得 (s,t) 相等的最小操作次数。

    (nle 5000)

    Solution

    考虑 (s_i e s_{i+1}) 的下标位置,假设 (s_i=0) 我们标记此处为 (0),否则标记为 (1)

    例如 001001011 标记为 .01.010.1

    我们不难发现 (s) 的标记序列是一个 01 交错的形式。

    然后我们发现一次操作其实是将一个标记往左/右移。

    我们发现最后的目标其实是将所有标记对齐。

    为了方便处理,我们强制让标记的开头为 (0)

    唯一的问题是对两端进行操作时导致答案的改变并不满足我们的规则。

    所以我们给两端补上 (infty) 个交错的标记。

    我们发现操作序列合法等价于任意两个相邻的标记距离都不大于 (2)

    我们发现答案的下界是将标记对齐后的下标差的和。

    事实上,下界总是可以达到的,这是因为初始状态合法,操作的过程中我们每次先抵着再走即可。

    所以我们只需要枚举从 (infty) 个交错的标记中额外取出多少个标记即可,然后 (mathcal O(n)) 计算答案,总体复杂度是 (mathcal O(n^2)) 的。

    要注意在一开始保证 (s) 生成的标记序列大于 (t)(反之亦然)然后用 (t) 去对齐。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std ;
    #define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
    #define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
    #define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
    #define re register
    int gi() {
    	char cc = getchar() ; int cn = 0, flus = 1 ;
    	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
    	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
    	return cn * flus ;
    }
    const int N = 5000 + 5 ; 
    const int inf = 1e9 + 7 ; 
    int n, g[N], f[N * 3], d[N * 3], cnt, num, Ans ; 
    char s[N], t[N] ;
    signed main()
    {
    	n = gi(), Ans = inf ;
    	scanf("%s", s + 1 ) ;
    	scanf("%s", t + 1 ) ; 
    	rep( i, 1, n ) s[i] -= '0', t[i] -= '0' ;
    	if(t[1] == 1) g[++ num] = 0 ; //begin with 0 
    	rep( i, 1, n - 1 ) if(t[i] != t[i + 1]) g[++ num] = i ;
    	if(t[n] == 1) g[++ num] = n ; int u = (num / 2) * 2 ; 
    	rep(i, 1, u) f[++ cnt] = 0 ; 
    	if(s[1] == 1) f[++ cnt] = 0 ;
    	rep( i, 1, n - 1 ) if(s[i] != s[i + 1]) f[++ cnt] = i ;
    	if(s[n] == 1) f[++ cnt] = n ; 
    	rep( i, 1, num ) f[++ cnt] = n ;
    	for(re int i = 0; i <= cnt - num; i += 2) {
    		int ans = 0 ;
    		rep( j, 1, i ) d[j] = 0 ;
    		rep( j, i + 1, i + num ) d[j] = g[j - i] ;
    		rep( j, i + num + 1, cnt ) d[j] = n ;
    		rep( j, 1, cnt ) ans += abs(f[j] - d[j]) ;
    		Ans = min( Ans, ans ) ; 
    	}
    	cout << Ans << endl ; 
    	return 0 ;
    }
    
  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/Soulist/p/13768233.html
Copyright © 2011-2022 走看看