码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4596:[Shoi2016]黑暗前的幻想乡

时间:2019-05-03 16:34:42      阅读:125      评论:0      收藏:0      [点我收藏+]

标签:mes   ++   namespace   set   break   line   print   ble   git   

传送门

这个题好像bzoj4455:[Zjoi2016]小星星
然后就可以类比那个思路将树形dp改为矩阵树定理,然后就做完了
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
#define rg register
const int maxn=20,mod=1e9+7;
int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
int del(int x,int y){return x-y<0?x-y+mod:x-y;}
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int n,k[maxn][maxn],tot,x[maxn][maxn*maxn],y[maxn][maxn*maxn],t[maxn],ans;
int mi(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=mul(ans,a);
        b>>=1,a=mul(a,a);
    }
    return ans;
}
int gauss(){
    for(rg int i=1;i<=n;i++)
        for(rg int j=1;j<=n;j++)
            k[i][j]=add(k[i][j],mod);
    bool flag=0;
    for(rg int i=1;i<n;i++){
        if(!k[i][i]){
            int w=0;
            for(rg int j=i+1;j<n;j++)if(k[j][i]){w=j;break;}
            swap(k[i],k[w]);flag^=1;
            if(!w)return 0;
        }
        int t=mi(k[i][i],mod-2);
        for(rg int j=1;j<n;j++)
            if(j!=i){
                int now=mul(t,k[j][i]);
                for(rg int h=i;h<n;h++)
                    k[j][h]=del(k[j][h],mul(k[i][h],now));
            }
    }
    int ans=1;
    for(rg int i=1;i<n;i++)ans=mul(ans,k[i][i]);
    return flag?(mod-ans):ans;
}
int main()
{
    read(n),tot=1<<(n-1);
    for(rg int i=1;i<n;i++){
        read(t[i]);
        for(rg int j=1;j<=t[i];j++)read(x[i][j]),read(y[i][j]);
    }
    for(rg int i=0;i<tot;i++){
        int now=0;memset(k,0,sizeof k);
        for(rg int j=1;j<n;j++)
            if(i&(1<<(j-1))){
                for(rg int h=1;h<=t[j];h++)
                    k[x[j][h]][x[j][h]]++,k[y[j][h]][y[j][h]]++,
                    k[x[j][h]][y[j][h]]--,k[y[j][h]][x[j][h]]--;
                now++;
            }
        if((n-now-1)&1)ans=del(ans,gauss());
        else ans=add(ans,gauss());
    }
    printf("%d\n",ans);
}

bzoj4596:[Shoi2016]黑暗前的幻想乡

标签:mes   ++   namespace   set   break   line   print   ble   git   

原文地址:https://www.cnblogs.com/lcxer/p/10805300.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!