HAOI2018 反色游戏

传送门

这个题一开始他们说什么列异或方程组我也不懂……根据学姐告诉我的结论,如果联通块内有一棵树的话,那么其他的非树边反转或者不反转都行,反正树是能给你还原回去的。不过如果有奇数个黑点是不行的。
根据这个结论,记录联通块个数为tot,那么不删点的时候答案就是\(2^{m-n+tot}\)
然后对于删点……和yyb大神学的……如果这个点是割点,那么首先我们看它所连接的联通块中有没有有奇数个黑点的,如果有就不行。
之后再看它上面的联通块中是否有奇数个黑点,有就不行。
如果这个联通块外也有奇数个黑点……还是不行……
否则的话答案就是在原来的基础上,减去点度,加上1,再加上获得的新联通块个数,原理和上面是一样的。
注意如果是根的话获得的新联通块个数要-1,因为上面没了。

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 100005;
const int mod = 1e9+7;

int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

struct edge
{
   int next,to,from;
}e[M<<1];

int n,m,head[M],ecnt,dfn[M],low[M],vis[M],idx,root,T;
int sum[M],c[M],d[M],f[M],deg[M],po[M<<1],a[M],val,tot,x,y;
char s[M];
void add(int x,int y){e[++ecnt] = {head[x],y,x},head[x] = ecnt,deg[y]++;}
void clear()
{
   ecnt = idx = val = tot = 0;
   rep(i,1,n) head[i] = dfn[i] = low[i] = deg[i] = d[i] = c[i] = f[i] = 0;
}

void tarjan(int x)
{
   dfn[x] = low[x] = ++idx,vis[x] = root,sum[x] = a[x];
   for(int i = head[x];i;i = e[i].next)
   {
      int t = e[i].to;
      if(!dfn[t])
      {
	 tarjan(t),sum[x] += sum[t];
	 low[x] = min(low[x],low[t]);
	 if(low[t] >= dfn[x]) d[x] |= (sum[t] & 1),c[x]++,f[x] += sum[t];
      }
      else low[x] = min(low[x],dfn[t]);
   }
   if(x == root) c[x]--;
}

int main()
{
   po[0] = 1;
   rep(i,1,(M<<1)-1) po[i] = (po[i-1] << 1) % mod;
   T = read();
   while(T--)
   {
      n = read(),m = read(),clear();
      rep(i,1,m) x = read(),y = read(),add(x,y),add(y,x);
      scanf("%s",s+1);
      rep(i,1,n) a[i] = s[i] - '0';
      rep(i,1,n) if(!dfn[i]) root = i,tarjan(i),tot++,val += sum[i] & 1;
      val ? printf("0 ") : printf("%d ",po[m-n+tot]);
      rep(i,1,n)
      {
	 if(d[i]) printf("0 ");
	 else if(val - (sum[vis[i]] & 1)) printf("0 ");
	 else if((sum[vis[i]] - a[i] - f[i]) & 1) printf("0 ");
	 else printf("%d ",po[m-n+tot-deg[i]+1+c[i]]);
      }
      enter;
   }
   return 0;
}

posted @ 2019-03-26 21:28  CaptainLi  阅读(191)  评论(0编辑  收藏  举报