HDU6073 Matching In Multiplication

题目链接

题意

​ 存在两个点集 U,V ,点集 U 中的每个点均向 V 连出两条带权无向边,选择特定的边能使 U,V 构成一个完全二分图。定义一个完全二分图的值为其所有边权值的乘积,求解 U,V 能构成的所有完全二分图的值的和。

分析

​ 注意到要构成完全二分图,即每个点要且仅被一条边所连接。所以考虑度数不确定的点集 V ,对于所有度数为1的点均是仅一种选择,小编采用搜索的方法对所有度数为1的点进行与确认,通过0,1交换的方式鉴别对应边是否肯定会被选中。递归的去除完所有度数为1的点后,剩下的部分必然组成 k 个联通块,同时每个点的度数 2 。设剩余 m 个点,点集 U 中的每个点度数为2,即剩余2m 条边,而点集 V 中有 m 个点,且度数 2 ,显然 V 中每个点的度数也均为2。连通块中所有点的度数均为2,则该联通块必然是一个环,那么构建完全二分图在该联通块中只需要间隔着取边即可,共2中方案。剩下的问题是如何计算,我们发现对于两个联通块,假设其建图后值分别为 a,bc,d 。那么最后的值为 ac+ad+bc+bd=a(c+d)+b(c+d)=(a+b)(c+d) 。故对每个联通块分别计算就能得到最后的答案了。详细不理解的对方可以看代码。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 300300
#define eps 1e-7
#define lson rt<<1
#define rson rt<<1|1
#define LL long long
const int mod=998244353;
struct Edge{
    int v;
    LL w;
    Edge(){}
    Edge(int _v,LL _w):v(_v),w(_w){}
};
vector<Edge> edge;
vector<int> g[MAXN*2];
int deg[MAXN*2];
int vis[MAXN*2];
LL cnt[2];
LL ans;
void addedge(int u,int v,LL w){
    g[u].push_back(edge.size());
    edge.push_back(Edge(v,w));
    deg[u]++;
}
void dfs(int u,int f,int flg){
    vis[u]=1;
    for(int i=0;i<g[u].size();++i){
        Edge &e = edge[g[u][i]];
        if(vis[e.v])
            continue;
        deg[e.v]--;
        if(flg)
            ans=(ans*e.w)%mod;
        if(deg[e.v]==1)
            dfs(e.v,u,1-flg);
    }
}
void dfs2(int u,int f,int idx){
    for(int i=0;i<g[u].size();++i){
        Edge &e = edge[g[u][i]];
        if(e.v==f || vis[e.v])
            continue;
        vis[e.v]=1;
        cnt[idx]=(cnt[idx]*e.w)%mod;
        dfs2(e.v,u,1-idx);
    }
}
int main(){
    int T,n,v;
    LL w;
    cin>>T;
    while(T--){
        scanf("%d",&n);
        edge.clear();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=2*n;++i){
            g[i].clear();
            deg[i]=0;
        }
        for(int i=1;i<=n;++i){
            for(int k=0;k<2;++k){
                scanf("%d %I64d",&v,&w);
                v+=n;
                addedge(i,v,w);
                addedge(v,i,w);
            }
        }
        ans=1;
        for(int i=n+1;i<=2*n;++i)
            if(deg[i]==1)
                dfs(i,0,1);
        for(int i=1;i<=2*n;++i)
            if(!vis[i]){
                cnt[0]=cnt[1]=1;
                dfs2(i,0,0);
                ans=(ans*(cnt[0]+cnt[1]))%mod;
            }
        printf("%I64d\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章