zoukankan      html  css  js  c++  java
  • Luogu4494 [HAOI2018]反色游戏 【割顶】

    首先发现对于一个联通块有奇数个黑点,那么总体来说答案无解。这个很容易想,因为对每个边进行操作会同时改变两个点的颜色,异或值不变。

    然后一个朴素的想法是写出异或方程进行高斯消元。

    可以发现高斯消元的过程实际上就是合并两个点的过程,如果是一棵树的话那么答案一定是2。

    对于树上每多的一条边,它在合并点的过程中会被消除掉,这意味着这个是一个自由元。所以我们发现连通图的答案是$2^{m-n+1}$。

    这样第一问答案就可以求了。判完无解后答案为$2^{m-n+d}$,$d$为联通块数。

    对于第二问,如果有超过两个联通块的黑点为奇数个,后面全部为0。

    现在考虑删除一个点,没有改变连通性,那么只有两种情况,一种是其它联通块仍然有奇数个黑点,答案为0,否则看自己这个联通块整体的黑点个数异或上当前删除的点的颜色,为奇数则答案为0,否则答案不难想。

    如果删除了一个点,改变了连通性,那么分别检查每个联通块的奇偶性,这个不难,答案也不难想。

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 const int maxn = 105000;
      5 const int mod = 1e9+7;
      6 
      7 int n,m,cnt;
      8 vector<int> g[maxn];
      9 int a[maxn],flag;
     10 
     11 int low[maxn],dfn[maxn],sz[maxn],cl,pa[maxn];
     12 int ans[maxn],pw2[maxn*2];
     13 
     14 void init(){
     15     memset(low,0,sizeof(low));
     16     memset(dfn,0,sizeof(dfn));
     17     memset(sz,0,sizeof(sz));
     18     memset(pa,0,sizeof(pa));
     19     memset(ans,0,sizeof(ans));
     20     memset(pw2,0,sizeof(pw2));
     21     memset(a,0,sizeof(a));
     22     for(int i=1;i<=n;i++) g[i].clear();
     23     n = m = cnt = flag = 0;
     24 }
     25 
     26 void dfs(int now,int fa){
     27     low[now] = dfn[now] = ++cl;
     28     pa[now] = fa; sz[now] = a[now];
     29     for(int i=0;i<g[now].size();i++){
     30     int z = g[now][i];
     31     if(z == fa || dfn[z] > dfn[now]) continue;
     32     if(dfn[z] == 0){
     33         dfs(z,now); sz[now]^=sz[z];
     34         low[now] = min(low[now],low[z]); 
     35     }else low[now] = min(low[now],dfn[z]);
     36     
     37     }
     38 }
     39 
     40 void dfs2(int now,int fa,int dr){
     41     for(int i=0;i<g[now].size();i++){
     42     if(pa[g[now][i]] != now) continue;
     43     dfs2(g[now][i],now,dr);
     44     }
     45     int isfuck = 0;
     46     if(flag - dr) {ans[now] = 0;return;}
     47     if(fa == 0){
     48     int mlgb = 0;
     49     for(int i=0;i<g[now].size();i++){
     50         if(pa[g[now][i]] != now) continue;
     51         mlgb++; isfuck += sz[g[now][i]];
     52     }
     53     if(mlgb == 0){ans[now] = ans[0];}
     54     else if(mlgb == 1){
     55         if(isfuck) ans[now] = 0;
     56         else ans[now] = pw2[m-g[now].size()-(n-1)+cnt];
     57     }else{
     58         if(isfuck) ans[now] = 0;
     59         else ans[now] = pw2[m-g[now].size()-(n-1)+(cnt-1+mlgb)];
     60     }
     61     }else{
     62     int mlgb = 0;
     63     for(int i=0;i<g[now].size();i++){
     64         if(pa[g[now][i]] != now) continue;
     65         if(low[g[now][i]] >= dfn[now]){
     66         mlgb++;
     67         isfuck += sz[g[now][i]];
     68         }
     69     }
     70     if(mlgb == 0){
     71         if(dr ^ a[now]) ans[now] = 0;
     72         else ans[now] = pw2[m-g[now].size()-(n-1)+cnt];
     73     }else{
     74         if(isfuck) ans[now] = 0;
     75         else if(dr^(isfuck&1)^a[now]) ans[now] = 0;
     76         else ans[now] = pw2[m-g[now].size()-(n-1)+(cnt+mlgb)];
     77     }
     78     }
     79 }
     80 
     81 void read(){
     82     scanf("%d%d",&n,&m);
     83     for(int i=1;i<=m;i++){
     84     int u,v; scanf("%d%d",&u,&v);
     85     g[u].push_back(v); g[v].push_back(u);
     86     }
     87     for(int i=1;i<=n;i++) scanf("%1d",&a[i]);
     88 }
     89 
     90 void work(){
     91     pw2[0] = 1;
     92     for(int i=1;i<=m*2;i++) pw2[i] = pw2[i-1]*2%mod;
     93     for(int i=1;i<=n;i++) {
     94     if(!dfn[i]) {
     95         dfs(i,0); cnt++;
     96         if(sz[i]) flag++;
     97     }
     98     }
     99     if(flag == 0){ans[0] = pw2[m-n+cnt];}
    100     if(flag >= 2){
    101     for(int i=0;i<=n;i++) printf("0 ");
    102     puts("");
    103     return;
    104     }
    105     for(int i=1;i<=n;i++) {
    106     if(pa[i] == 0){dfs2(i,0,sz[i]);}
    107     }
    108     for(int i=0;i<=n;i++) printf("%d ",ans[i]);
    109     puts("");
    110 }
    111 
    112 int main(){
    113     int T; scanf("%d",&T);
    114     while(T--){
    115     init();
    116     read();
    117     work();
    118     }
    119     return 0;
    120 }
  • 相关阅读:
    学区房概念
    VMwareworkstationfull8.0.2591240.exe
    VMwareworkstationfull8.0.4744019.exe
    .net伪静态
    将DataTable中的某一行复制到另一个新的DataTable(转)
    js服务器端控件Label 与TextBox RadioButtonList 与 DropDownList 的值
    Iframe刷新父窗口的几种方式
    记录一下ListItem类的常用的方法
    ASP.net中的Repeater控件嵌套
    记录一条自己常用的分页存储过程
  • 原文地址:https://www.cnblogs.com/Menhera/p/10511726.html
Copyright © 2011-2022 走看看