zoukankan      html  css  js  c++  java
  • [agc006f]blackout

    题意:

    给你一个$n imes n$的网格,开始有$m$个被涂成黑色的格子,如果存在三个格子$(x,y)$,$(y,z)$,$(z,x)$满足$(x,y)$,$(y,z)$均为黑格子且$(z,x)$为白格子,那么就将$(z,x)$涂黑,问最后会有多少个被涂黑的格子。

    题解:

    神仙题。。。感觉正解比C题还神仙。。。

    用矩阵直接构造非常麻烦,矩阵甚至构造不出来,那么可以考虑对每个黑格子$(x,y)$,从$x$向$y$连边,那么问题就转化到了有向图上。(真是让人只能跪地膜的构造,场上完全没这样想过。。。)这样整个矩阵就变成了一个邻接矩阵,题意就变成了如果图中有两条边$<x,y>$,$<y,z>$,那么就连一条边$<z,x>$;

    显然每个弱联通块之间没有关系,所以每个联通块单独考虑。大(sui)胆(bian)证(shou)明(wan)之后可以发现几个性质:

    1.一条长度为2的链会变成一个三元环;

    2.一个二元环会形成一个自环;

    3.只要形成自环,那么整个联通块就会变成一个完全图

    所以考虑判断这个联通块有没有自环or二元环,这个有固定技巧,即将原图三染色(012染色),然后分类讨论:

    1.如果染色失败(即颜色冲突),那么说明联通块中出现了自环或二元环,变成了完全图,那么直接把边数平方即可;

    2.如果三种颜色没有全部出现,说明图中没有长度大于一的链,此时不会出现新的边,即不会出现新格子;

    3.如果染色成功且三种颜色都出现了,那么答案就是0的点向1的连边,1的点向2的连边,2的点向3的连边,直接乘起来即可;

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long ll;
     8 struct edge{
     9     int v,w,next;
    10 }a[500001];
    11 int n,m,u,v,c[3],cnt,_cnt,cc[500001],tot=0,head[500001];
    12 bool used[500001],ok;
    13 ll ans=0;
    14 void add(int u,int v,int w){
    15     a[++tot].v=v;
    16     a[tot].w=w;
    17     a[tot].next=head[u];
    18     head[u]=tot;
    19 }
    20 void dfs(int u){
    21     c[cc[u]]++;
    22     used[u]=true;
    23     cnt++;
    24     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
    25         int v=a[tmp].v;
    26         if(a[tmp].w==1)_cnt++;
    27         if(!used[v]){
    28             cc[v]=(cc[u]+a[tmp].w+3)%3;
    29             dfs(v);
    30         }else if(cc[v]!=(cc[u]+a[tmp].w+3)%3)ok=false;
    31     }
    32 }
    33 int main(){
    34     memset(head,-1,sizeof(head));
    35     memset(cc,-1,sizeof(cc));
    36     memset(used,0,sizeof(used));
    37     scanf("%d%d",&n,&m);
    38     for(int i=1;i<=m;i++){
    39         scanf("%d%d",&u,&v);
    40         add(u,v,1);
    41         add(v,u,-1);
    42     }
    43     for(int i=1;i<=n;i++){
    44         if(!used[i]){
    45             c[0]=c[1]=c[2]=cnt=_cnt=0;
    46             ok=1;
    47             cc[i]=0;
    48             dfs(i);
    49             if(!ok)ans+=(ll)cnt*cnt;
    50             else if(c[0]&&c[1]&&c[2])ans+=(ll)c[0]*c[1]+(ll)c[0]*c[2]+(ll)c[1]*c[2];
    51             else ans+=_cnt;
    52         }
    53     }
    54     printf("%lld",ans);
    55     return 0;
    56 }
  • 相关阅读:
    关于子类中不能调用基类中定义的事件问题
    比尔·盖茨在哈佛大学毕业典礼上的演讲
    一个QA讲解的回文判断函数
    mybatis和spring整合时这个报错,应该这样解决!
    “老师,为什么我一上课就感到困,听课听的总是走神?”
    最好的方法,是为你们量身定制!
    “桌面日历”记录的事件居然是看某某视频……
    干货!sqlserver数据库所有知识点总结整理,含代码(挺全的)
    越优秀的人越努力,越努力的人越幸运!
    挺不喜欢下雪的
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9520804.html
Copyright © 2011-2022 走看看