• [Atcoder Grand Contest 006 F][AGC006F] Blackout [染色]


    题面

    传送门

    思路

    首先,这个涂黑的方法我们来优化一下模型(毕竟当前这个放到矩形里面,你并看不出来什么规律qwq)

    我们令每个行/列编号为一个点,令边(x,y)表示一条从x到y的有向边

    那么显然只要有一条长度为2的路径,就会得到一个三元环

    我们考虑如何统计新加入的边的数量,发现有如下规律:

    1.如果一个弱联通块中的点可以被3染色(0的出边染成1,1的染成2,2的染成0,倒着染就是反过来),那么这个联通块中所有0会向所有1连边,所有1会向所有2连边,所有2会向0连边

    2.如果一个弱联通块染色的时候会遇到一个点染了2种颜色,那么这个联通块会变成一个团(一个有向完全图)

    3.如果一个弱联通块染完色了,只用了1或者2种颜色,那么这个联通块不会增加新的边

    然后这题就做完了

    Code

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cassert>
    #define ll long long
    using namespace std;
    inline int read(){
        int re=0,flag=1;char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-') flag=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
        return re*flag;
    }
    int n,m,first[100010],cnte=-1,col[100010],vis[200010];ll cnt[3],cntn,cntm;
    struct edge{
        int to,next;
    }a[200010];
    inline void add(int u,int v){
        a[++cnte]=(edge){v,first[u]};first[u]=cnte;
        a[++cnte]=(edge){u,first[v]};first[v]=cnte;
    }
    bool dfs(int u,int f,int type){
        int i,v,re=1,w;col[u]=(col[f]+type+3)%3;cnt[col[u]]++;cntn++;
        for(i=first[u];~i;i=a[i].next){
            v=a[i].to;w=(i%2?1:-1);
            if(vis[i]||vis[i^1]) continue;
            else cntm++,vis[i]=vis[i^1]=1;
            if(col[v]==-1) re&=dfs(v,u,w);
            else{
                if(col[v]!=(col[u]+w+3)%3) re=0,cnt[0]=cnt[1]=cnt[2]=1e9;
            }
        }
        return re;
    }
    int main(){
        memset(first,-1,sizeof(first));
        n=read();m=read();int i,t1,t2;ll ans=0;
        for(i=1;i<=m;i++){
            t1=read();t2=read();
            add(t1,t2);
        }
        memset(col,-1,sizeof(col));
        for(i=1;i<=n;i++){
            if(~col[i]) continue;
            memset(cnt,0,sizeof(cnt));cntn=cntm=0;
            if(dfs(i,0,1)){
                if(!cnt[0]||!cnt[1]||!cnt[2]) ans+=cntm;
                else ans+=cnt[0]*cnt[1]+cnt[1]*cnt[2]+cnt[2]*cnt[0];
            }
            else{
                if(!cnt[0]||!cnt[1]||!cnt[2]) ans+=cntm;
                else ans+=cntn*cntn;
            }
        } 
        cout<<ans;
    }
    
  • 相关阅读:
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 翻硬币 反转(开关问题)
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 高僧斗法 博弈论
    读书笔记 《如何阅读一本书》
    蓝桥杯 试题 历届试题 格子刷油漆
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
    读书笔记 《如何阅读一本书》
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9602864.html
Copyright © 2020-2023  润新知