1. 程式人生 > >UOJ #138. 【UER #3】開學前的塗鴉

UOJ #138. 【UER #3】開學前的塗鴉

head ont scrip 中一 std == i+1 last des

Description

紅包是一個有藝術細胞的男孩子。
紅包由於NOI慘掛心情不好,暑假作業又多,於是他開始在作業本上塗鴉。
一開始,他在紙上畫了一棵 n 個節點的樹。但是他覺得這樣的畫太簡單了,體現不出他高超的繪畫功底,於是他又額外畫上了 k 條邊。
然而他覺得這樣畫面太復雜,於是想刪去一些邊使得這個無向圖仍然是連通的。
請幫紅包求出刪邊的方案數。兩個方案被認為是不同的當且僅當存在一條邊在其中一組中被刪而另一組中沒有。(什麽邊都不刪也算一種方案)

Solution

首先發現可能被刪除的邊一定是在環上的,如果我們構出一棵樹來,那麽剩下的非樹邊一定都是反祖邊,並且反祖邊的條數不超過 \(10\)
\(Dzy Loves Chinese II\)

的方法做,我們給所有非樹邊一個權值,然後把跨過的樹邊都異或上這個權值(樹上差分實現就好了)
那麽不連通的情況就是存在一個子集異或和為 \(0\).
但是邊樹太多了不好枚舉,我們縮邊:把權值相同的一條鏈縮為以條邊,這條邊權值 \(w\) 為與它相同相同的邊的數目(刪這條邊有 \(w\) 種選擇),縮點後的樹的一種方案對應原圖中 \(\Pi w_i\) 中方案
縮完之後的邊不會很大,具體數字和證明見 \(UOJ\) 題解,大約是一個 \(bell\)
然後在一邊搜索的時候用一邊用線性基判掉不合法的方案就行了

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+50,mod=998244353;
int head[N],nxt[N*2],to[N*2],num=1,n,m,dep[N],st[N],top=0,w[N],cnt=0;
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void dfs(int x,int last){
    for(int i=head[x];i;i=nxt[i]){
        if(i==last)continue;
        int u=to[i];
        if(!dep[u]){
            dep[u]=dep[x]+1;dfs(u,i^1);w[x]^=w[u];
            if(w[u])st[++top]=w[u];
        }
        else if(dep[u]<dep[x]){
            w[x]^=1<<cnt;w[u]^=1<<cnt;
            st[++top]=(1<<cnt++);
        }
    }
}
int b[1005][15],ans=0;
struct data{int w,v;}e[N];
inline void bfs(int x,int t){
    if(x==cnt+1){
        ans=(ans+t)%mod;
        return ;
    }
    memcpy(b[x],b[x-1],sizeof(b[x]));
    bfs(x+1,t);
    for(int i=10,c=e[x].w;i>=0;i--){
        if(!(c>>i&1))continue;
        if(!b[x][i]){b[x][i]=c;break;}
        else c^=b[x][i];
        if(!c)return ;
    }
    bfs(x+1,1ll*t*e[x].v%mod);
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  int x,y;
  scanf("%d%d",&n,&m);m=n+m-1;
  for(int i=1;i<=m;i++){
      scanf("%d%d",&x,&y);
      link(x,y);link(y,x);
  }
  dep[1]=1;dfs(1,1);
  sort(st+1,st+top+1);cnt=0;
  for(int i=1,t=1;i<=top;i++,t++)
      if(i==top || st[i]!=st[i+1])e[++cnt]=(data){st[i],t},t=0;
  bfs(1,1);
  printf("%d\n",ans);
  return 0;
}

UOJ #138. 【UER #3】開學前的塗鴉