• Solution -「AGC 026D」Histogram Coloring


    (mathcal{Description})

      Link.

      有 (n) 列下底对齐的方格纸排成一行,第 (i) 列有 (h_i) 个方格。将每个方格染成黑色或白色,求使得任意完整 (2 imes2) 矩形内恰有两个白色(和两个黑色)的方案数。答案模 (10^9+7)

      (nle100)(h_ile10^9)

    (mathcal{Solution})

      小清新 DP 题叭。

      首先考虑在完整的网格图里染色,若某一行完成染色,那么下一行的方案并不多:

    • 若当前行存在相邻同色格,则下一行必须为当前行颜色取反;
    • 否则即当前行为黑白或白黑交替,则下一行可以与当前行全部相同或全部相反。

      把这一结论放在本题,建出小根笛卡尔树(根据题意,当前区间最小值应缩为一点,严格意义上不是笛卡尔树,不难意会 qwq),DP。转移问题形如将若干小块网格下面垫一大块完整网格图,求方案数。所以,令 (f(u,0/1)) 表示完成 (u) 所代表区间的染色,且最下一层是否是黑白交替状的方案数。转移平凡,可参考易读的代码。

      转移里有个快速幂,最终复杂度为 (mathcal O(nlog h))

    (mathcal{Code})

    /* Clearink */
    
    #include <cstdio>
    
    #define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
    #define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i )
    
    const int MAXN = 100, MOD = 1e9 + 7;
    int n, h[MAXN + 5];
    
    int node, ecnt, lef[MAXN + 5], rig[MAXN + 5],
    	hgt[MAXN + 5], tot[MAXN + 5], head[MAXN + 5];
    struct Edge { int to, nxt; } graph[MAXN + 5];
    
    inline int mul( const long long a, const int b ) { return a * b % MOD; }
    inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
    inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
    inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
    inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
    inline int mpow( int a, int b ) {
    	int ret = 1;
    	for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
    	return ret;
    }
    
    inline void link( const int s, const int t ) {
    	graph[++ecnt] = { t, head[s] }, head[s] = ecnt;
    }
    
    inline int build( const int l, const int r ) {
    	if ( l > r ) return 0;
    	
    	int u = ++node;
    	hgt[u] = 0x3f3f3f3f, tot[u] = 0;
    	lef[u] = l, rig[u] = r;
    	rep ( i, l, r ) {
    		if ( h[i] < hgt[u] ) hgt[u] = h[i], tot[u] = 0;
    		tot[u] += h[i] == hgt[u];
    	}
    
    	for ( int i = l, j; i <= r; i = j + 1 ) {
    		if ( h[j = i] == hgt[u] ) continue;
    		while ( j + 1 <= r && h[j + 1] != hgt[u] ) ++j;
    		int v = build( i, j );
    		link( u, v ), hgt[v] -= hgt[u];
    	}
    
    	return u;
    }
    
    int f[MAXN + 5][2];
    
    inline void solve( const int u ) {
    	int &f0 = f[u][0] = 1, &f1 = f[u][1] = 2, len = rig[u] - lef[u] + 1;
    	for ( int i = head[u], v; i; i = graph[i].nxt ) {
    		solve( v = graph[i].to ), len -= rig[v] - lef[v] + 1;
    		f0 = mul( f0, add( f[v][0], add( f[v][1], f[v][1] ) ) ),
    		f1 = mul( f1, f[v][1] );
    	}
    	f0 = mul( f0, mpow( 2, len ) ),
    	subeq( f0, f1 ),
    	f1 = mul( f1, mpow( 2, hgt[u] - 1 ) );
    }
    
    int main() {
    	scanf( "%d", &n );
    	rep ( i, 1, n ) scanf( "%d", &h[i] );
    
    	solve( build( 1, n ) );
    	printf( "%d
    ", add( f[1][0], f[1][1] ) );
    	return 0;
    }
    
    
  • 相关阅读:
    Javascript 基础知识整理
    设计模式
    Flex 布局
    CSS选择器,属性前缀,长度单位,变形效果,过渡效果,动画效果
    CSS中一些重要概念
    性能优化(CSS优化)
    CSS定位走一波(定位学习续)
    定位布局
    浮动布局
    Display属性学习总结
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14728085.html
Copyright © 2020-2023  润新知