zoukankan      html  css  js  c++  java
  • [ARC109F] 1D Kingdom Builder

    题目

    点这里看题目。

    分析

    这种问题我们通常可以考虑合法染色方案的等价条件。

    一步简单的转化是,将染色看成删除。此时要求就是,如果删除一个孤立的格子且不是最后一个格子,那么其它连续段的两端的颜色必须全部不同于当前格颜色

    基于此,对于合法的染色方案,我们可以尝试构造删除方案:

    除了最后一个被删除的段之外,我们总能找到某一个步骤,使得该步骤的状态为:被操作段之外的所有段两端颜色都相同(例如某个段被删除干净的时候)。那么记其余段两端颜色为 (overline{c}) ,记其补色为 (c)

    那么借助这个机会,我们必然可以让所有包含 (c) 的段全部删掉。剩余的段,就只会包含 (overline{c}) 。可以发现这样的段最多只能有一个,所以它就是最后被删除的段。

    上面这个过程我们说明了 " 合法的染色方案必然有一种所述的删除方案 " ,而如果有所述的删除方案,显然该染色方案是合法的。即 " 存在一种所述删除方案 " (Leftrightarrow) " 该染色方案合法 "

    整理一下,我们可以直接枚举 (c) ,那么有如下限制:

    1. 对于第一个被删除的段,即最后被染色的段,必须包含子序列 (c)
    2. 对于中间被删除的段,即中间被染色的段,它和它两边必须包含子序列 (overline{c}coverline{c})
    3. 对于最后被删除的段,即第一个被染色的段,它和它两边必须包含子序列 (overline{c}overline{c})

    知道了限制,我们就可以开始 DP 了。我们可以设状态:

    (f(i,0/1,0/1)) :当 (i) 强制不选时,是否存在最后被删的段,是否存在第一个被删的段,此时的最小覆盖数。

    转移的时候,我们可以使用类似于 子序列自动机 的指针迅速定位最近的合法转移点。由于此时的一组前缀都是合法的,所以我们需要用一些辅助变量记录前缀的最小值。

    最后,注意只有一段的方案总是合法的,所以需要单独计算只有一段的结果

    小结:

    1. 构造方案,寻找合法方案的等价条件的思路值得再次强调。
    2. 贪心的删除思想也是比较巧妙的。
    3. 寻找条件的过程一定要细致,不要错过任何细小的条件。

    代码

    #include <cstdio>
    #include <cstring>
    
    #define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; (i) ++ )
    #define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; (i) -- )
    
    const int MAXN = 1e5 + 100;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MIN( const _T a, const _T b )
    {
    	return a < b ? a : b;
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    int fir[2], las[2], nei[2][2];
    int tf[MAXN], tl[MAXN], tn[MAXN];
    int pre[MAXN][2], dp[MAXN][2][2];
    
    char S[MAXN];
    int s[MAXN], t[MAXN];
    int N, ans;
    
    void Upt( int &x, const int v ) { x = MIN( x, v ); }
    int Pre( const int x, const int c ) { return x <= 0 ? -1 : pre[x][c]; }
    
    void Init()
    {
    	N += 3; 
    	s[1] = 0, s[N - 1] = s[N] = 1;
    	t[1] = t[N - 1] = t[N] = 0;
    	
    	int mx = 0, mn = N;
    	rep( i, 1, N ) if( t[i] )
    		mx = MAX( mx, i ), Upt( mn, i );
    	ans = mx - mn + 1;
    	pre[1][0] = pre[1][1] = -1;
    	rep( i, 2, N )
    		pre[i][0] = ( s[i - 1] ? pre[i - 1][0] : i - 1 ),
    		pre[i][1] = ( s[i - 1] ? i - 1 : pre[i - 1][1] );
    }
    
    int Calc( const int c )
    {
    	int _c = c ^ 1;
    	rep( i, 1, N )
    		tf[i] = Pre( Pre( i + 1, _c ) - 1, _c ),
    		tl[i] = Pre( i, c ) - 1,
    		tn[i] = Pre( Pre( Pre( i + 1, _c ), c ), _c );
    	memset( dp, 0x3f, sizeof dp );
    	memset( fir, 0x3f, sizeof fir );
    	memset( las, 0x3f, sizeof las );
    	memset( nei, 0x3f, sizeof nei );
    	dp[0][0][0] = 0;
    	int pf = 0, pl = 0, pn = 0;
    	rep( i, 1, N )
    	{
    		if( t[i] ) continue;
    		for( ; pf <= tf[i] ; pf ++ )
    			rep( k, 0, 1 ) Upt( fir[k], dp[pf][0][k] - pf );
    		for( ; pl <= tl[i] ; pl ++ )
    			rep( k, 0, 1 ) Upt( las[k], dp[pl][k][0] - pl );
    		for( ; pn <= tn[i] ; pn ++ )
    			rep( j, 0, 1 ) rep( k, 0, 1 )
    				Upt( nei[j][k], dp[pn][j][k] - pn );
    		memcpy( dp[i], dp[i - 1], sizeof dp[i - 1] );
    		Upt( dp[i][0][0], nei[0][0] + i - 1 );
    		Upt( dp[i][1][0], MIN( nei[1][0], fir[0] ) + i - 1 );
    		Upt( dp[i][0][1], MIN( nei[0][1], las[0] ) + i - 1 );
    		Upt( dp[i][1][1], MIN( nei[1][1], MIN( fir[1], las[1] ) ) + i - 1 );
    	}
    	return dp[N][1][1];
    }
    
    int main()
    {
    	read( N );
    	scanf( "%s", S + 1 );
    	rep( i, 1, N ) s[i + 1] = S[i] == 'b';
    	scanf( "%s", S + 1 );
    	rep( i, 1, N ) t[i + 1] = S[i] == 'o';
    	
    	Init();
    	write( MIN( ans, MIN( Calc( 0 ), Calc( 1 ) ) ) ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    20165105 学习基础和C语言基础调查
    2017-2018网络攻防第四周作业
    2017-2018-2 20165233 实验三 敏捷开发与XP实践
    20165233 2017-2018-2 《Java程序设计》第九周学习总结
    Linux学习笔记(一)
    第三周学习总结
    数据结构C++,线性表学习
    uname()系统调用学习
    cd
    go连接数据库并执行文件中的sql语句
  • 原文地址:https://www.cnblogs.com/crashed/p/14359279.html
Copyright © 2011-2022 走看看