ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「CF1368G」Shifting Dominoes

2021-10-18 20:05:42  阅读:186  来源: 互联网

标签:const int Graph return CF1368G Shifting 骨牌 Dominoes MAXN


题目

点这里看题目。

分析

先考虑枚举一个骨牌并将它取下来。这样,一个空格就可以通过周围的骨牌来向各个方向移动。

注意到,我们可以选取最终局面上的一个空格,并找出它原先在哪里——看一下初始平板上这个空格对应的字符,就可以确定现在这块骨牌向哪个方向移动了,我们就可以逆向操作;一直循环直到这个空格属于取下的那一块骨牌。

容易发现,每个空格只会对应一个逆向操作的结果,在图上考虑,也就是只会连出一条边。最终我们会得到两片基环树森林(我们可以通过二染色来划分某一棵树属于哪一片森林),不妨设为 \(F_1,F_2\)。

但是,我们真的可以得到环吗?如果尝试去画出一个带环的平板,你会发现这出奇地困难——甚至是不可能的。下面我们会加以证明:

假设每一小格内部都有一个格点。如果说平板上面出现了一个环,我们可以用 Pick 定理计算一下这个环内部格点的数量:

\[b=S-\frac{a}{2}+1 \]

其中 \(a\) 为边上的格点数目,\(S\) 为面积,\(b\) 为内部的格点数目。

不难发现 \(\frac a 2\) 一定是偶数。从环上任选一个起点,则相对于它,最终环上的 \(\sum \Delta x=\sum\Delta y=0\)。又由于每经过一条边,\(x\) 或者 \(y\) 的变化量是一定的,所以在 \(x,y\) 分量上走过的步数一定是偶数;每走一步,边上的格点增加两个,因此 \(a\) 为 4 的倍数。

也不难发现 \(S\) 一定是偶数。使用向量外积计算 \(S\),由于每条边长度为偶数,则 \(2S\) 为 4 的倍数。

所以 \(S-\frac{a}{2}\) 为偶数,则 \(b\) 为奇数。

因此,我们得到的 \(F_1,F_2\) 是实实在在的森林,而不是变异的基环树森林

显然,如果某个方案中的两个空格为 \(c_1\) 和 \(c_2\),那么二染色后两者一定颜色不同,我们不妨设 \(c_1\in F_1,c_2\in F_2\)。此时,我们尝试让 \(c_1\) 和 \(c_2\) 分别去移动(显然它们只能跳向根),如果它们经过的结点中,不存在一对结点属于同一骨牌,那么 \((c_1,c_2)\) 这一对也一定不可能被生成。反之,则一定可以生成:在所有在两条路径上均有结点出现的骨牌中,取出其中在 \(c_1\) 的路径上第一次出现的那一块骨牌,则 \(c_1\) 和 \(c_2\) 可以互不干扰地移动到这块骨牌的位置。

因此,需要求的就是到根的路径上存在一对结点属于同一骨牌的 \((c_1,c_2)\)。简单容斥一下可以求那些不存在一对结点属于同一骨牌的 \((c_1,c_2)\)。这就简单多了,DFS \(F_1\),并在 \(F_2\) 的子树上打标记即可。

复杂度为 \(O(nm\log nm)\)。

小结:

  1. 学会转化题目的条件。此题中如果没有转化好 \((c_1,c_2)\) 的合法条件,就会很难下手;
  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;

#ifdef _DEBUG
const int MAXN = 105;
#else
const int MAXN = 2e5 + 5;
#endif

template<typename _T>
void read( _T &x )/*{{{*/
{
    x = 0; char s = getchar(); bool f = false;
    while( ! ( '0' <= s && s <= '9' ) ) { f = s == '-', s = getchar(); }
    while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
    if( f ) x = -x;
}/*}}}*/

template<typename _T>
void write( _T x )/*{{{*/
{
    if( x < 0 ) putchar( '-' ), x = -x;
    if( 9 < x ) write( x / 10 );
    putchar( x % 10 + '0' );
}/*}}}*/

struct MyGraph/*{{{*/
{
    struct Edge/*{{{*/
    {
        int to, nxt;
        Edge(): to( 0 ), nxt( 0 ) {}
    }Graph[MAXN];/*}}}*/

    int head[MAXN], cnt;
    int DFN[MAXN], siz[MAXN], ID;

    MyGraph(): head{}, cnt( 0 ), DFN{}, siz{}, ID( 0 ) {}

    Edge operator [] ( const int &idx ) const { return Graph[idx]; }

    void AddEdge( const int from, const int to )/*{{{*/
    {
        Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
        head[from] = cnt;
    }/*}}}*/

    void DFS( const int u )/*{{{*/
    {
        DFN[u] = ++ ID, siz[u] = 1;
        for( int i = head[u] ; i ; i = Graph[i].nxt )
            DFS( Graph[i].to ), siz[u] += siz[Graph[i].to];
    }/*}}}*/
};/*}}}*/

MyGraph tre[2];

char grid[MAXN], str[MAXN];
int cmpn[MAXN];

int su[MAXN << 2], cov[MAXN << 2];

LL ans = 0;
int N, M;

#define ID( x, y ) ( ( (x) - 1 ) * M + (y) )

inline bool Inside( const int x, const int y )
{ return 1 <= x && x <= N && 1 <= y && y <= M; }

inline void Cover( const int x, const int delt, const int leaf )/*{{{*/
{
    if( cov[x] += delt ) su[x] = 0;
    else su[x] = leaf ? 1 : su[x << 1] + su[x << 1 | 1];
}/*}}}*/

inline void Upt( const int x ) { su[x] = cov[x] ? 0 : su[x << 1] + su[x << 1 | 1]; }

void Build( const int x, const int l, const int r )/*{{{*/
{
    if( l > r ) return ; su[x] = cov[x] = 0;
    if( l == r ) { su[x] = l > 1; return ; }
    int mid = ( l + r ) >> 1;
    Build( x << 1, l, mid );
    Build( x << 1 | 1, mid + 1, r );
    Upt( x );
}/*}}}*/

inline void Cover( const int x, const int l, const int r, const int segL, const int segR, const int delt )/*{{{*/
{
    if( segL > segR ) return ;
    if( segL <= l && r <= segR ) { Cover( x, delt, l == r && l > 1 ); return ; }
    int mid = ( l + r ) >> 1;
    if( segL <= mid ) Cover( x << 1, l, mid, segL, segR, delt );
    if( mid  < segR ) Cover( x << 1 | 1, mid + 1, r, segL, segR, delt );
    Upt( x );
}/*}}}*/

int Query( const int x, const int l, const int r, const int segL, const int segR )/*{{{*/
{
    if( segL > segR ) return 0;
    if( segL <= segR ) return su[x];
    int mid = ( l + r ) >> 1, ret = 0;
    if( segL <= mid ) ret += Query( x << 1, l, mid, segL, segR );
    if( mid  < segR ) ret += Query( x << 1 | 1, mid + 1, r, segL, segR );
    return ret;
}/*}}}*/

void DFS( const int u )/*{{{*/
{
    if( u )
    {
        int d = tre[1].DFN[cmpn[u]], s = tre[1].siz[cmpn[u]];
        Cover( 1, 1, tre[1].ID, d, d + s - 1, 1 );
        ans -= su[1]; 
    }
    for( int i = tre[0].head[u] ; i ; i = tre[0][i].nxt ) 
        DFS( tre[0][i].to );
    if( u ) 
    {
        int d = tre[1].DFN[cmpn[u]], s = tre[1].siz[cmpn[u]];
        Cover( 1, 1, tre[1].ID, d, d + s - 1, -1 );
    }
}/*}}}*/

int main()
{
    read( N ), read( M );
    rep( i, 1, N )
    {
        scanf( "%s", str + 1 );
        rep( j, 1, M ) grid[ID( i, j )] = str[j];
    }
    rep( i, 1, N ) rep( j, 1, M )
    {
        int col = ( i + j ) & 1, tx, ty;
        if( grid[ID( i, j )] == 'L' ) tx = i, ty = j + 2, cmpn[ID( i, j )] = ID( i, j + 1 );
        if( grid[ID( i, j )] == 'R' ) tx = i, ty = j - 2, cmpn[ID( i, j )] = ID( i, j - 1 );
        if( grid[ID( i, j )] == 'U' ) tx = i + 2, ty = j, cmpn[ID( i, j )] = ID( i + 1, j );
        if( grid[ID( i, j )] == 'D' ) tx = i - 2, ty = j, cmpn[ID( i, j )] = ID( i - 1, j );
        if( ! Inside( tx, ty ) ) tre[col].AddEdge( 0, ID( i, j ) );
        else tre[col].AddEdge( ID( tx, ty ), ID( i, j ) );
    }
    ans = 1ll * ( N * M / 2 ) * ( N * M / 2 );
    tre[1].DFS( 0 );
    Build( 1, 1, tre[1].ID );
    DFS( 0 );
    write( ans ), putchar( '\n' );
    return 0;
}

标签:const,int,Graph,return,CF1368G,Shifting,骨牌,Dominoes,MAXN
来源: https://www.cnblogs.com/crashed/p/15422041.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有