AT2167 [AGC006F] Blackout

Description

縦、横ともに $ N $ マスのマス目があります。 上から $ i $ マス目、左から $ j $ マス目のマスを ( $ i $ , $ j $ ) と表します。

最初、 $ M $ 個のマスが黒く塗られており、それ以外のマスはすべて白です。 具体的には、マス ( $ a_1 $ , $ b_1 $ ), ( $ a_2 $ , $ b_2 $ ), $ ... $ , ( $ a_M $ , $ b_M $ ) が黒く塗られています。

すぬけ君は次のルールに従い、可能な限りマスを黒く塗っていきます。

- ある $ 1 leq x,y,z leq N $ について、マス ( $ x $ , $ y $ ), ( $ y $ , $ z $ ) がともに黒で、マス ( $ z $ , $ x $ ) が白ならば、マス ( $ z $ , $ x $ ) を黒く塗る。

すぬけ君が可能な限りマスを黒く塗ったとき、最終的に黒いマスは何個になるかを求めてください。

Solution

发现按照题意描述可以画出一个三元环,于是把每个黑色视为一条连边,在图上用三种颜色循环染色

如果没有将三种颜色用完,不能画出新的边,答案为边数

如果不能正确染色,那么将会形成一个完全图,答案为点数的平方

如果可以正确染色,所有相邻颜色都会连边,分三类计算

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,head[100005],tot,col[100005],cnt[3],siz,num;
long long ans;
bool tag;
struct Edge
{
    int to,nxt,w;
}edge[200005];
inline int read()
{
    int f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return f*w;
}
void dfs(int k,int c)
{
    col[k]=c+1,cnt[c]++,siz++;
    for(int i=head[k];i;i=edge[i].nxt)
    {
        int v=edge[i].to;
        if(edge[i].w==1) num++;
        if(!col[v]) dfs(v,(c+edge[i].w+3)%3);
        else if(col[v]!=(c+edge[i].w+3)%3+1) tag=true;
    }
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read();
        edge[++tot]=(Edge){v,head[u],1},head[u]=tot,edge[++tot]=(Edge){u,head[v],-1},head[v]=tot;
    }
    for(int i=1;i<=n;i++)
    {
        if(!col[i])
        {
            tag=false,cnt[0]=cnt[1]=cnt[2]=siz=num=0;
            dfs(i,0);
            if(tag) ans+=1ll*siz*siz;
            else if(!cnt[2]||!cnt[1]||!cnt[0]) ans+=1ll*num;
            else ans+=1ll*cnt[0]*cnt[1]+1ll*cnt[0]*cnt[2]+1ll*cnt[1]*cnt[2];
        }
    }
    printf("%lld
",ans);
    retu
Blackout
原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14074461.html