CF1299D Around the World

cf題面
洛谷題面
題解:
將全部1連出的邊(咱們稱之爲「關鍵邊」)刪掉,獲得若干個連通塊。
因爲1號節點不會包含在 \(\geq\) 4的環裏,
若是咱們單獨考慮一個連通塊,那麼它只多是下面兩種狀況之一(這裏套用了cf官方題解的圖):


如今考慮題目的限制條件:
一個連通塊知足條件的充要條件是:連通塊裏的全部環對應的邊權異或和都能插入一個線性基裏。
證實?衆所周知,線性基裏的數亦或起來不能爲0。(不知道的請百度
而後再回過頭來看上述的兩種連通塊:
第一種:只有1條關鍵邊,那麼只有兩種貢獻:
1.空的線性基(刪掉);2.下面連通塊獲得的線性基(不刪)。
第二種:2條關鍵邊,因此有3種狀況:
1.空的線性基(刪掉);2.下面連通塊獲得的線性基(刪一條邊);
3.下面連通塊+包含紅邊的那個環獲得的線性基。
接下來考慮合併這些貢獻。
因爲\(w\)在二進制下只有5位,本質不一樣的5位的線性基個數只有374個,
因此咱們能夠把這些合法的線性基都預處理出來,並將每一個線性基表示爲一個狀態。
\(f_{i,j}\) 表示前\(i\)個連通塊,合併後獲得線性基\(j\)的方案數。
轉移時一個一個把貢獻合併上去就好。(合併就是線性基的合併)
注意到不一樣的線性基可能本質相同,咱們須要讓線性基惟一,這個能夠參考一下個人insert函數:c++

IN insert(int *a,int x){
    FOR(i,4,0){
        if(!x)return 0;
        if(!((x>>i)&1))continue;
        if(!a[i]){
            a[i]=x;
            FOR(j,i-1,0)if((a[i]>>j)&1)a[i]^=a[j];
            F(j,i+1,4)if((a[j]>>i)&1)a[j]^=a[i];
            return 1;
        }
        x^=a[i];
    }
    return 0;
}

大概就是若是這一位是1而且有這一位的線性基,就把這個1消掉。
DP數組能夠滾動優化。
時間複雜度:O(374* \(log_w\) +(n+m) \(log_w\) +374*n)
代碼:git

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
    res=0;register D g=1;register char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
const int Mod=1e9+7;
IN insert(int *a,int x){
    FOR(i,4,0){
        if(!x)return 0;
        if(!((x>>i)&1))continue;
        if(!a[i]){
            a[i]=x;
            FOR(j,i-1,0)if((a[i]>>j)&1)a[i]^=a[j];
            F(j,i+1,4)if((a[j]>>i)&1)a[j]^=a[i];
            return 1;
        }
        x^=a[i];
    }
    return 0;
} 
struct B{
    int b[6];
    friend bool operator < (B x,B y){
        F(i,0,4)if(x.b[i]!=y.b[i])return x.b[i]<y.b[i];
        return 0;
    }
    friend bool operator == (B x,B y){
        F(i,0,4)if(x.b[i]!=y.b[i])return 0;
        return 1;
    }
}bas[440],now;
map<B,int>mp;
struct E{
    int to,nt,w;
}e[202000];
#define T e[k].to
int n,m,sn,ans,cnt,X,Y,W,tot,sum,c[440][440],val[101000],dep[101000],head[101000],t[6],vis[101000],f[101000][440];
I Add(int &x,int y){
    (x+=y)>=Mod?x-=Mod:0;
}
IN rnk(B a){
    //cout<<mp[a]<<endl;
    if(!mp[a]){
        cout<<"!";
        F(i,0,4)cout<<a.b[i]<<" ";
        cout<<endl;
        system("pause");
    }
    return mp[a];
    re l=1,r=tot,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(a==bas[mid])return mid;
        if(a<bas[mid])r=mid-1;
        else l=mid+1;
    }
    return mid;
}
IN Plus(B x,B y){
    B tmp;C(tmp.b,0);
    memcpy(tmp.b,x.b,sizeof(tmp.b));
    F(i,0,4){
        if(!y.b[i])continue;
        if(!insert(tmp.b,y.b[i]))return 0;
    }
    return rnk(tmp);
}
I add(int x,int y,int w){
    e[++sum].to=y;e[sum].nt=head[x];head[x]=sum;e[sum].w=w;
}
I D_1(int p,int w){
    if(p==5){
        tot++;F(i,0,4)bas[tot].b[i]=t[i];//,cout<<t[i]<<" ";
        //cout<<endl;system("pause");
        return;
    }
    F(i,0,(1<<p)-1)
        if((w&i)==0){
            t[p]=(1<<p)|i;
            D_1(p+1,w|(1<<p));
        }
    t[p]=0;
    D_1(p+1,w);
}
inline bool bbb(B x,B y){
    re ca=0,cb=0;
    F(i,0,4)ca+=(x.b[i]!=0),cb+=(y.b[i]!=0);
    return ca<cb;
}
I init(){
    tot=0;D_1(0,0);
    sort(bas+1,bas+1+tot);F(i,1,tot)mp[bas[i]]=i;
    F(i,1,tot)F(j,1,tot)c[i][j]=Plus(bas[i],bas[j]);
}
I D_2(int x,int fa,int depth,int V){
    val[x]=V;dep[x]=depth;
    for(re k=head[x];k!=-1;k=e[k].nt){
        if(T==fa||vis[T]!=-1||T==1)continue;
        if(dep[T]&&dep[x]<dep[T])sn&=insert(now.b,val[x]^val[T]^e[k].w);//cout<<"loop"<<(val[x]^val[T]^e[k].w)<<endl;
        if(dep[T])continue;
        D_2(T,x,depth+1,V^e[k].w);
    }
}
I DP(int i,int rk){F(j,1,tot)Add(f[i][c[rk][j]],f[i-1][j]);}//F(j,1,tot)if(f[i][j])cout<<"!"<<rk<<" "<<i<<" "<<j<<endl;}
int main(){
    init();//cout<<tot<<endl;
    read(n);read(m);C(head,-1);sum=-1;
    F(i,1,m){
        read(X);read(Y);read(W);add(X,Y,W);add(Y,X,W);
    }
    f[0][1]=1;C(vis,-1);
    for(re k=head[1];k!=-1;k=e[k].nt)vis[T]=e[k].w;
    cnt=0;
    F(i,2,n){
        if(vis[i]==-1)continue;//cout<<"@"<<endl;
        C(now.b,0);X=0;W=0;cnt++;sn=1;
        for(re k=head[i];k!=-1;k=e[k].nt)if(vis[T]!=-1){
            X=T;W=e[k].w;break;
        }
        D_2(i,0,1,0);if(X)D_2(X,0,1,0);
        DP(cnt,1);
        //cout<<"sn="<<sn<<endl;
        if(sn){
            //F(i,0,4)cout<<now.b[i]<<" ";
            //cout<<endl;
            if(!X)DP(cnt,Y=rnk(now));//,cout<<Y<<endl;
            else{
                DP(cnt,Y=rnk(now));DP(cnt,rnk(now));//cout<<Y<<endl;
                if(insert(now.b,vis[i]^vis[X]^W))DP(cnt,Y=rnk(now));//cout<<Y<<endl;
            }
        }
        vis[i]=vis[X]=-1;
    }
    ans=0;
    F(i,1,tot)Add(ans,f[cnt][i]);
    cout<<ans;
    return 0;
}
相關文章
相關標籤/搜索