• 【HAOI2018】反色游戏


    题面

    https://www.luogu.org/problem/P4494

    题解

    $2018$蛤省省选神仙题。

    前置知识:线性基。$orz aysn$

    关键的一个结论:在一个任意的联通块内,如果它的黑点个数为偶数个,则“联通块内的目标”是可以达到的。设点数为$n$,边数为$m$,则方案数为$2^{m-n+1}$,这个结论的证明需要线性基,将任意一个生成树内的边全部插入线性基,就构成了一个可以表达任意数的线性基,可以证明,加入其他的边是冗杂的,无论线性基外的边怎么选,线性基里面的边总可以使他变回全$0$的状态。如果任意一个线性基中的边不按它“应该”在的状态,都是不行的。当黑点的个数为奇数个时,是无法通过异或得到的。

    所以直接$tarjan$一发就好了,三个判断分别是判断去掉$x$后下面的点双是不是奇数个黑点、其他联通块是不是奇数个黑点、$x$上面的点双是不是奇数个黑点。

    突然想起来刘汝佳紫书上的一道题,和异或有关的,是研学游在大巴上想的,也许和这个有关吧。

    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define N 100500
    #define mod 1000000007
    #define ri register int
    
    using namespace std;
    
    inline int read() {
      int ret=0; char ch=getchar();
      while (ch<'0' || ch>'9') ch=getchar();
      while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar();
      return ret;
    }
    
    vector<int> to[N];
    char ch[N];
    int n,m,a[N],mi[N<<1];
    int dfn[N],low[N],vis[N],clc,rt;
    int sum[N],c[N],d[N],f[N],dg[N];
    
    void init() {
      clc=0;
      for (ri i=1;i<=n;i++) dfn[i]=low[i]=d[i]=c[i]=f[i]=0;
      for (ri i=1;i<=n;i++) to[i].clear();
    }
    
    void tarjan(int x) {
      dfn[x]=low[x]=++clc; vis[x]=rt; sum[x]=a[x];
      for (ri i=0;i<to[x].size();i++) {
        int y=to[x][i];
        if (!dfn[y]) {
          tarjan(y); low[x]=min(low[x],low[y]);
          sum[x]+=sum[y];
          if (low[y]>=dfn[x]) {
            d[x]|=(sum[y]&1),c[x]++,f[x]+=sum[y];
          }
        }
        else low[x]=min(low[x],dfn[y]);
      }
      if (x==rt) c[x]--;
    }
    
    int main() {
      mi[0]=1;
      for (ri i=1;i<(N<<1);i++) mi[i]=(mi[i-1]<<1)%mod;
      int T=read();
      while (T--) {
        n=read();m=read();init();
        int val=0,tot=0;
        for (ri i=1;i<=m;i++) {
          int u=read(),v=read();
          to[u].push_back(v);
          to[v].push_back(u);
        }
        for (ri i=1;i<=n;i++) dg[i]=to[i].size();
        scanf("%s",ch+1);
        for (ri i=1;i<=n;i++) a[i]=ch[i]-'0';
        for (ri i=1;i<=n;i++) if (!dfn[i]) {
          rt=i;
          tarjan(i);
          ++tot;
          val+=sum[i]&1;
        }
        printf("%d ",val?0:mi[m-n+tot]);
        for (ri i=1;i<=n;i++) {
          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 ",mi[m-n+tot-dg[i]+1+c[i]]);
        }
        puts("");
      }
      return 0;
    }
  • 相关阅读:
    计数排序
    CSS3变形
    前端内存泄露问题
    复杂对象的深拷贝
    JavaScript基本数据类型——Symbol
    随机打乱数组
    唯一重复的数字
    src和href的区别
    iframe的缺点
    link和@import的区别
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11432748.html
Copyright © 2020-2023  润新知