[Luogu4494] [BZOJ5303] [LOJ2524]

LOJ有数据就是好

原题解,主要是代码参考

对于每一个联通块(n个点),其他的边一开始随便选,只需要n-1条边就可以确定最终结果.

所以设\(cnt\)为联通块数 , 答案为 \(2^{m-n+cnt}\)

还有就是有解的情况必须是黑点个数为偶数,还要注意有删掉这个点可能使无解变有解,这比从有解变无解更难想

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
} const int MAXN=100005;
const int MAXM=200005;
const int mod=1e9+7; struct Edge{
int v,w,c,next;
}e[MAXM];
int first[MAXN],Ecnt=1;
inline void Add_edge(int u,int v,int w=0,int c=0){
e[++Ecnt]=(Edge){v,w,c,first[u]};
first[u]=Ecnt;
} int ctg[MAXN],size[MAXN],sub[MAXN],low[MAXN],dfn[MAXN],deg[MAXN],cut[MAXN],pow2[MAXN];
bool flag[MAXN];
char S[MAXN];
int n,m,T,ans,odd,dft,cnt,rt; inline void clear(){
memset(size,0,sizeof size);
memset(deg,0,sizeof deg);
memset(sub,0,sizeof sub);
memset(cut,0,sizeof cut);
memset(low,0,sizeof low);
memset(dfn,0,sizeof dfn);dft=0;
memset(first,0,sizeof first);Ecnt=0;
cnt=0,odd=0;
} inline void tarjan(int u,int pre=0){
low[u]=dfn[u]=++dft;
flag[u]=1;
size[u]=(S[u]=='1');//算黑点数量
ctg[u]=rt;//这种情况下方便后面调用
for(int i=first[u];i;i=e[i].next){
int v=e[i].v;
if(!dfn[v]){
tarjan(v,u);
size[u]+=size[v];
if(low[v]>=dfn[u]){
cut[u]++;
flag[u]&=((size[v]&1)==0);//子树不合法可以直接标记
sub[u]+=size[v];
}
else low[u]=min(low[u],low[v]);
}
else if (v!=pre) low[u]=min(low[u],dfn[v]);
}
if(!pre) cut[u]--;//删掉u以后能增加几个连通分量
} int main(){
pow2[0]=1;
for(int i=1;i<MAXN;i++) pow2[i]=(pow2[i-1]<<1)%mod;
T=read();
while(T--){
n=read(),m=read();
clear();
for(int i=1;i<=m;i++){
int x=read(),y=read();
Add_edge(x,y);
Add_edge(y,x);
deg[x]++,deg[y]++;
}
scanf("%s",S+1);
for(int i=1;i<=n;i++) if(!dfn[i]){
//ctgn++;//这里不适合这样用
rt=i,cnt++;
tarjan(i);
odd+=size[i]&1;
}
ans=m-n+cnt;
printf("%d",odd?0:pow2[ans]);//只要有偶数个黑点就是无解的
for(int i=1;i<=n;i++){
if(!deg[i]) printf(" %d",odd-size[i]==0?pow2[ans]:0);//以后复杂题目估计都得写成这样
else{
//子树合法 父亲那一块合法 也许不合法变为合法
if((flag[i]) && (((size[ctg[i]]-(S[i]=='1')-sub[i])&1)==0) && (odd-(size[ctg[i]]&1)==0))
printf(" %d",pow2[ans-deg[i]+1+cut[i]]);
else printf(" 0");
}
}
printf("\n");
}
}

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

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

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

  2. bzoj 5393 [HAOI2018] 反色游戏

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

  3. P4494 [HAOI2018]反色游戏

    P4494 [HAOI2018]反色游戏 题意 给你一个无向图,图上每个点是黑色或者白色.你可以将一条边的两个端点颜色取反.问你有多少种方法每个边至多取反一次使得图上全变成白色的点. 思路 若任意一个 ...

  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. 洛谷P4494 [HAOI2018]反色游戏(tarjan)

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

随机推荐

  1. os.chdir("/deepmatching") OSError: [Errno 2] No such file or directory: '/deepmatching'

    #os.chdir("/deepmatching")os.chdir(os.path.dirname(os.path.abspath("deepmatching1&quo ...

  2. 【转】LVS/Nginx如何处理session问题

    原文地址:http://network.51cto.com/art/201005/200279.htm 通过设置persistence的值,使session会话保持. [51CTO.com独家特稿]业 ...

  3. IFM设备 Linux方面资料

    Github: https://github.com/lovepark/ifm3d

  4. while循环for循环优缺点和应用

    while循环常用于那种不知道循环次数是多少的情况,比如让用户循环输入一个整数,直到输入某个特殊的字符为止,你根本没法直到这个循环会进行的次数. for循环多用于循环次数比较明确的情况,比如for(n ...

  5. Apr编程

    一.简介 http://www.xuebuyuan.com/2195578.html   二.教程 http://dev.ariel-networks.com/apr/

  6. openpyxl模块处理excel文件

    python模块之——openpyxl 处理xlsx/ xlsm文件 项目原因需要编辑excel文件,经过查询,最先尝试xlwt .wlrd这个两个模块,但是很快发现这两个模块只能编辑xls文件,然而 ...

  7. Appium混合应用测试

    Appium测试混合应用 混合应用即是原生应用中间混着html页面,需要在两种类型的页面之间跳转. 测试Android混合应用 前期设置 4.4以下版本使用automationName:Selendr ...

  8. python -Tkinter 实现一个小计算器功能

    文章来源:http://www.cnblogs.com/Skyyj/p/6618739.html 本代码是基于python 2.7的 如果是对于python3.X  则需要将 tkinter 改为Tk ...

  9. RecyclerView添加两种布局

    简介: 本篇博客主要介绍如何在RecyclerView中添加两种布局 思路:主要重写Recyclerview.Adapter中的一些方法 1.public int getItemViewType(in ...

  10. Android使用Canvas画图

    1.参考:http://blog.csdn.net/rhljiayou/article/details/7212620/ 2.常用方法: 1.Canvas类 drawArc 绘制弧 drawBitma ...