P4494 [HAOI2018]反色游戏

题意

给你一个无向图,图上每个点是黑色或者白色。你可以将一条边的两个端点颜色取反。问你有多少种方法每个边至多取反一次使得图上全变成白色的点。

思路

若任意一个连通块黑色点的个数为奇数那么无解。

先考虑树的情况。发现如果是树,并且黑点个数为偶数,有且仅有一种方式达到目标。然后发现,对于一个无向图,它的任意一个生成树若有解,那么其他非树边无论是否取反都有且仅有一种情况达到目标,并且充分。所以答案就是 \(2^{m-n+1}\)。

考虑不联通的情况,每多一个连通块相当于少了一条非树边,所以答案就是 \(2^{m-n+cnt( 连通块个数 )}\)。

然后考虑对于删除每个点的情况,分为以下几种:

  1. 独立点,不与任何其他点联通,判断删去后是否有解;
  2. 非割点,判断删去后是否有解。具体来讲,该点为黑点时,当且仅当全局只有一个连通块且正是所属连通块无解时删除后有解。白点时类似。
  3. 是割点,判断删去该点后出现的所有连通块是否有解,并且也要判断是否仅有一个连通块无解且正是该点导致无解时删掉后有解。

对于每种情况,按照上面的方式计算一下有解时的新图的答案即可。

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cctype>
  5. #include<cstring>
  6. #include<cmath>
  7. using namespace std;
  8. inline int read(){
  9. int w=0,x=0;char c=getchar();
  10. while(!isdigit(c))w|=c=='-',c=getchar();
  11. while(isdigit(c))x=x*10+(c^48),c=getchar();
  12. return w?-x:x;
  13. }
  14. namespace star
  15. {
  16. const int maxn=1e5+10,mod=1e9+7;
  17. int n,m,pow[maxn],in[maxn];
  18. int ecnt,head[maxn],to[maxn<<1],nxt[maxn<<1];
  19. inline void addedge(int a,int b){
  20. to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt,in[a]++ ;
  21. to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt,in[b]++;
  22. }
  23. int bel[maxn],dfn[maxn],low[maxn],cut[maxn],cnt[maxn],cntbel[maxn],cutcnt[maxn];
  24. bool col[maxn],unsol[maxn],unsolbel[maxn];
  25. void tarjan(int x,int fa){
  26. bel[x]=bel[0],cutcnt[x]=cnt[x]=col[x];
  27. dfn[x]=low[x]=++dfn[0];
  28. for(int u,i=head[x];i;i=nxt[i]) if((u=to[i])!=fa)
  29. if(!dfn[u]) {
  30. tarjan(u,x),low[x]=min(low[x],low[u]);
  31. cnt[x]+=cnt[u];
  32. if(dfn[x]<=low[u]) cutcnt[x]+=cnt[u],++cut[x],unsol[x]|=cnt[u]&1;
  33. }else low[x]=min(low[x],dfn[u]);
  34. cut[x]-=!fa;
  35. }
  36. inline void work(){
  37. memset(head,0,sizeof head),ecnt=bel[0]=0;memset(dfn,0,sizeof dfn),memset(cut,0,sizeof cut),memset(in,0,sizeof in),memset(unsol,0,sizeof unsol);
  38. n=read(),m=read();
  39. for(int i=1;i<=m;i++) addedge(read(),read());
  40. for(int c,i=1;i<=n;i++) scanf("%1d",&c),col[i]=c;
  41. int cntunsol=0;
  42. for(int i=1;i<=n;i++) if(!dfn[i])
  43. bel[0]++,tarjan(i,0),cntunsol+=cnt[i]&1,cntbel[bel[0]]=cnt[i],unsolbel[bel[0]]=cntbel[bel[0]]&1;
  44. int ans=m-n+bel[0];
  45. printf("%d ",cntunsol?0:pow[ans]);
  46. for(int i=1;i<=n;i++) {
  47. if(!in[i]) printf("%d ",cntunsol^cnt[i]?0:pow[ans]);
  48. else if(!cut[i]){
  49. if((unsolbel[bel[i]] and !(cntunsol^col[i])) or (!unsolbel[bel[i]] and !cntunsol and !col[i]))
  50. printf("%d ",pow[ans-in[i]+1+cut[i]]);
  51. else printf("0 ");
  52. }else if(!unsol[i] and !((cntbel[bel[i]]-cutcnt[i])&1) and !(cntunsol-unsolbel[bel[i]]))
  53. printf("%d ",pow[ans-in[i]+1+cut[i]]);
  54. else printf("0 ");
  55. }
  56. puts("");
  57. }
  58. }
  59. signed main(){
  60. star::pow[0]=1;
  61. for(int i=1;i<=100000;i++) star::pow[i]=(star::pow[i-1]<<1)%star::mod;
  62. int T=read();
  63. while(T--)star::work();
  64. return 0;
  65. }

P4494 [HAOI2018]反色游戏的更多相关文章

  1. 洛谷P4494 [HAOI2018]反色游戏(tarjan)

    题面 传送门 题解 我们先来考虑一个联通块,这些关系显然可以写成一个异或方程组的形式,形如\(\oplus_{e\in edge_u}x_e=col_u\) 如果这个联通块的黑色点个数为奇数,那么显然 ...

  2. 【BZOJ5303】[HAOI2018]反色游戏(Tarjan,线性基)

    [BZOJ5303][HAOI2018]反色游戏(Tarjan,线性基) 题面 BZOJ 洛谷 题解 把所有点全部看成一个\(01\)串,那么每次选择一条边意味着在这个\(01\)串的基础上异或上一个 ...

  3. bzoj 5393 [HAOI2018] 反色游戏

    bzoj 5393 [HAOI2018] 反色游戏 Link Solution 最简单的性质:如果一个连通块黑点个数是奇数个,那么就是零(每次只能改变 \(0/2\) 个黑点) 所以我们只考虑偶数个黑 ...

  4. 【loj#2524】【bzoj5303】 [Haoi2018]反色游戏(圆方树)

    题目传送门:loj bzoj 题意中的游戏方案可以转化为一个异或方程组的解,将边作为变量,点作为方程,因此若方程有解,方程的解的方案数就是2的自由元个数次方.我们观察一下方程,就可以发现自由元数量=边 ...

  5. [BZOJ5303] [HAOI2018] 反色游戏

    题目链接 LOJ:https://loj.ac/problem/2524 BZOJ:https://lydsy.com/JudgeOnline/problem.php?id=5303 洛谷:https ...

  6. [BZOJ5303][HAOI2018]反色游戏(Tarjan)

    暴力做法是列异或方程组后高斯消元,答案为2^自由元个数,可以得60分.但这个算法已经到此为止了. 从图论的角度考虑这个问题,当原图是一棵树时,可以从叶子开始唯一确定每条边的选择情况,所以答案为1. 于 ...

  7. bzoj 5303: [Haoi2018]反色游戏

    Description Solution 对于一个有偶数个黑点的连通块,只需要任意两两配对,并把配对点上的任一条路径取反,就可以变成全白了 如果存在奇数个黑点的连通块显然无解,判掉就可以了 如果有解, ...

  8. Luogu4494 [HAOI2018]反色游戏 【割顶】

    首先发现对于一个联通块有奇数个黑点,那么总体来说答案无解.这个很容易想,因为对每个边进行操作会同时改变两个点的颜色,异或值不变. 然后一个朴素的想法是写出异或方程进行高斯消元. 可以发现高斯消元的过程 ...

  9. [HAOI2018]反色游戏

    [Luogu4494] [BZOJ5303] [LOJ2524] LOJ有数据就是好 原题解,主要是代码参考 对于每一个联通块(n个点),其他的边一开始随便选,只需要n-1条边就可以确定最终结果. 所 ...

随机推荐

  1. python_selenium 之logging模块入门及调用实战

    一.logging模块是什么? 是Python内置的标准模块,主要用于输出运行日志 二.日志的作用 日志是代码的必要组成部分 记录日志能显示程序当前运行状态 出问题后定位当时问题 三.python日志 ...

  2. NX二次开发-获取面的外围边和孔槽边

    函数: UF_MODL_ask_face_loops()  获取面的所有封闭边组合(多组edge) UF_MODL_ask_loop_list_count() 获取loop的数量(面上孔.槽的数量+1 ...

  3. 【NX二次开发】不健全的双击按钮。

    为什么说不健全,是因为 双击按钮时会先运行单击事件,这个后面再解决.但是模仿某公司的图层操作工具是没有问题了,因为这个工具运行双击事件时本来就需要运行单击事件,不仔细看容易被唬住. 图层操作工具(双击 ...

  4. 【C++】共用体\联合体(union)

    共用体的用法与结构体差不多,只不过将关键字由struct变成了union.共用体使不同的类型变量存放到同一段内存单元中,所以共用体在同一时刻只能存储一个数据成员的值,共用体的大小等于最大成员的大小(结 ...

  5. 懒人 IDEA 插件推荐:EasyCode 一键帮你生成所需代码

    Easycode是idea的一个插件,可以直接对数据的表生成entity,controller,service,dao,mapper,无需任何编码,简单而强大. 1.安装(EasyCode) 我这里的 ...

  6. 【模板】O(nlongn)求LIS

    合理运用单调性降低复杂度 平常用的都是O(n^2)的dp求LIS(最长不下降子序列)这里介绍O(nlogn)的算法 分析 对于可能出现的x<y<i且A[y]<A[x]<A[i] ...

  7. 【codeforces841A】Generous Kefa

    原题 A. Generous Kefatime limit per test:2 secondsmemory limit per test:256 megabytes input:standard i ...

  8. Feign Client 原理和使用

    Feign Client 原理和使用 一块石头 ​ 公众号:好奇心森林 ​关注他 创作声明:内容包含虚构创作 6 人赞同了该文章 最近一个新项目在做后端HTTP库技术选型的时候对比了Spring We ...

  9. Linux主机解析顺序

    1.介绍 本篇文章由于因公司项目上线,需要对项目环境进行压力测试.在压测过程中,所有打压机从公网对目标项目服务器进行压力测试,发现和内网压力测试的性能结果差距10倍左右,在调整主机对DNS的解析顺序之 ...

  10. Pandas高级教程之:plot画图详解

    目录 简介 基础画图 其他图像 bar stacked bar barh Histograms box Area Scatter Hexagonal bin Pie 在画图中处理NaN数据 其他作图工 ...