• [AGC035E] Develop


    题目

    点这里看题目。

    分析

    AGC 的难题都很巧妙

    对于这种 " 操作 + 计数 " 题目,我们常用方法是分析任意局面可以被操作出来的充要条件

    当然,这也不是一敲脑门就能想出来的

    对于这道题,我们不妨考虑删除的先后顺序。比如,如果 (x-2) 最终被删除,那么必然有 (x)(x-2) 之前被删除;同理, (x+k) 在同样条件下有 (x)(x+k) 之前被删除。

    因此我们可以对于任意局面,找出其中被删除的集合 (D) 。对于 (xin D) ,由于我们要求 (x-2)(x+k)(x) 之后删除,所以可以连接有向边 (x ightarrow x-2)(x ightarrow x+k) 。此时如果图中出现了圈,那么显然就是不合法的,自己不可能在自己之前删除;反过来,如果不存在圈,那么按照拓扑序进行删除必然是可行的。

    因此得到:局面可以被操作当且仅当其对应的图中不存在圈

    由于图本身是静态的,只是 (D) 在变,所以我们可以在图上面决策 (D) 。注意到图的大致形态与 (K) 的奇偶性相关,分类讨论:

    • (K) 是偶数,此时图是两个连通块,并且连通块内部为 链 + 反向边 。这种情况就是要求不存在连续的 (K+1) 个点被选,怎么操作都可以。

    • (K) 是奇数,此时图为两条链,中间有一些跨链的边。为了图的简洁,我们不妨让一些边平行于边框,这里选择的是奇点指向偶点的边。当 (K=3) 时,下图是一个不错的参考:

      graph.png

      显然图上最短的环上有 (K+2) 个点,可以表示为: (a ightarrow a-2 ightarrow dots ightarrow b-k ightarrow b ightarrow b-2 ightarrow dots ightarrow a-k)(a) 是奇数而 (b) 是偶数 )。可以发现环的序列按照 向上 + 向右 + 向上 排列;又由于我们的序列必须接到右边的向上部分,因此需要再记录当前右边连续向上的长度。

      于是可以定义 DP 状态如下:

      (f(i,j,k)) :第 (i) 层,从该层左边出发的序列最长为 (j) ,从该层右边起的连续被选节点有 (k) 个的方案数。

      转移有些细节,建议参考代码。其实转移很简洁,如果你写的很长可以考虑重构

    小结:

    1. 此类问题的常用转化方法非常重要!
    2. 对于环,将其简化拆分成序列的思想也很重要。

    代码

    #include <cstdio>
    
    #define rep( i, a, b ) for( int (i) = (a) ; (i) <= (b) ; ++ (i) )
    #define per( i, a, b ) for( int (i) = (a) ; (i) >= (b) ; -- (i) )
    
    typedef long long LL;
    
    const int MAXN = 155;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0; char s = getchar(); int f = 1;
    	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
    	while( '0' <= s && 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;
    	if( 9 < x ) write( x / 10 );
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    int N, K, mod;
    
    LL Mul( LL x, int v ) { return x * v % mod; }
    int Sub( int x, int v ) { return ( x -= v ) < 0 ? x + mod : x; }
    int Add( int x, int v ) { return ( x += v ) >= mod ? x - mod : x; }
    
    namespace EvenK
    {
    	int f[MAXN];
    	
    	void Solve()
    	{
    		f[0] = 1, K >>= 1;
    		rep( i, 1, N )
    		{
    			rep( j, MAX( 1, i - K ), i )
    				f[i] = Add( f[i], f[j - 1] );
    			if( i <= K ) f[i] = Add( f[i], 1 );
    		}
    		write( Mul( f[N >> 1], f[N + 1 >> 1] ) ), putchar( '
    ' );
    	}
    }
    
    namespace OddK
    {
    	int f[MAXN << 1][MAXN][MAXN];
    	
    	void Solve()
    	{
    		f[0][0][0] = 1; int lst = 0;
    		for( int i = 2 ; i - K <= N ; i += 2 )
    		{
    			rep( j, 0, K + 1 ) rep( k, 0, N )
    				f[i][0][0] = Add( f[i][0][0], f[i - 2][j][k] );
    			//Both Ignored
    			if( i <= N )
    				rep( j, 0, K + 1 ) rep( k, 0, N )
    					f[i][0][k + 1] = Add( f[i][0][k + 1], f[i - 2][j][k] );
    			//Left Ignored, Right Chosen
    			if( i - K >= 1 )
    				rep( k, 0, N )
    				{
    					rep( j, 1, K ) //Must be connected to the Right, so we don't assume that the transfer is available if j = 0
    						f[i][j + 1][0] = Add( f[i][j + 1][0], f[i - 2][j][k] );
    					f[i][0][0] = Add( f[i][0][0], f[i - 2][0][k] );
    				}
    			//Left Chosen, Right Ignored
    			if( i <= N && i - K >= 1 )
    				rep( k, 0, N )
    					for( int j = 0 ; MAX( k + 1, j ) <= K ; j ++ )
    						f[i][MAX( k + 2, j + 1 )][k + 1] = Add( f[i][MAX( k + 2, j + 1 )][k + 1], f[i - 2][j][k] );
    			//Both Chosen
    			lst = i;
    		}
    		int ans = 0;
    		rep( j, 0, K + 1 ) rep( k, 0, N )
    			ans = Add( ans, f[lst][j][k] );
    		write( ans ), putchar( '
    ' );
    	}
    }
    
    int main()
    {
    	read( N ), read( K ), read( mod );
    	if( K % 2 == 0 ) EvenK :: Solve();
    	else OddK :: Solve();
    	return 0;
    }
    
  • 相关阅读:
    约数个数 和 约数之和
    二分模板
    新生赛补题
    codefores刷题心得3 思维+dp(特别好玩)
    二叉树的遍历及例题
    团队作业七——团队作业分配
    WarPlane——游戏设计文档
    团队作业(五)
    团队作业(四)
    团队项目方案分析
  • 原文地址:https://www.cnblogs.com/crashed/p/14279760.html
Copyright © 2020-2023  润新知