• 哪一天她能重回我身边 换根+基环树


    Solution

    将每个卡片反面数字向正面数字(值域(1~2n))建边,若能通过翻转边的方向使每个点的入度不大于(1),则达到目标
    对于’使每个点的入度不大于(1),我们让其构成一棵树,(根节点入度为(0)
    最终答案:最小次数=(sum各联通块最小次数),方案数=(prod各联通块最小次数的个数)
    对于每个联通块,边数(m),点数(n)

    (m==n-1)
    (dfs)出联通块中任意一点(x)(f[x]),即以(x)为根,总翻转次数。
    (dfs)一遍得出每个点的(f[]),取个(min),并找一下有几个(min)

    (m==n)
    基环树,只有两种情况,选一条环上的边((ed_{id})),符合要求的图的根节点只能是这条边两端端点((S和T))之一
    先忽略这条边,最后把这条边指向根节点,算出(f[S],f[T]).取(min)及找(min)个数((1或2))

    (m>n) 一定无法达到

    处理的时候建成双向边,(cnt)初始为1,用来判断父边和判断正面向反面的边。

    code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <vector>
    #include <cctype>
    using namespace std;
    char buf[1<<20],*p1,*p2;
    #define rint register int
    #define gc() (p1==p2?(p2=buf+fread(p1=buf,1,1<<20,stdin),p1==p2?EOF:*p1++):*p1++)
    #define read() ({
    	rint x=0;register char ch=gc();
    	while(!isdigit(ch)) ch=gc();
    	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch&15),ch=gc();
    	x;
    })
    const int maxn=2e5+5,M=998244353;
    int f[maxn];
    int S,T,ed_id;
    int ans,ans_cnt;
    int n,cnt,head[maxn];
    int node_cnt,edge_cnt;
    bool vis[maxn],jud;
    struct Edge{
    	int to,next;
    }e[maxn*2];
    vector < int > vec;
    void Init(){
    	cnt=1,jud=0,ans=0,ans_cnt=1;
    	memset(head,0,sizeof head);
    	memset(vis,0,sizeof vis);
    	memset(f,0,sizeof f);
    }
    void Aedge(rint x,rint y){
    	e[++cnt].to=y;
    	e[cnt].next=head[x];
    	head[x]=cnt;
    }
    void dfs(rint x){
    	vis[x]=1,node_cnt++;
    	for(rint i=head[x];i;i=e[i].next){
    		const rint y=e[i].to;
    		edge_cnt++;
    		if(vis[y]) continue;
    		dfs(y);
    	}
    }
    void dfs1(rint x,rint prt){
    	vis[x]=1;
    	for(rint i=head[x];i;i=e[i].next){
    		const rint y=e[i].to;
    		if(y==prt) continue;
    		if(vis[y]) S=x,T=y,ed_id=i;
    		else{
    			dfs1(y,x);
    			f[x]+=f[y]+(i&1);
    		}
    	}
    }
    void dfs2(rint x,rint prt){
    	vec.push_back(f[x]);
    	for(rint i=head[x];i;i=e[i].next){
    		const rint y=e[i].to;
    		if(y==prt||i==ed_id||i==(ed_id^1)) continue;
    		f[y]=f[x]+((i&1)?-1:1);
    		dfs2(y,x);
    	}
    }
    int main(){ 
    	//freopen("back10.in","r",stdin);
    	//freopen("1.out","w",stdout);
    	freopen("back.in","r",stdin);
    	freopen("back.out","w",stdout);
    	rint cs=read();
    	while(cs--){
    		Init();
    		n=read();
    		for(rint i=1,x,y;i<=n;++i){
    			x=read(),y=read();
    			Aedge(y,x),Aedge(x,y);
    		}
    		for(rint i=1;i<=n*2;++i){
    			if(vis[i]) continue;
    			node_cnt=0,edge_cnt=0;
    			dfs(i);
    			if(edge_cnt/2>node_cnt){ jud=1;break; }
    		}
    		if(jud){ printf("-1 -1
    ");continue; }
    		memset(vis,0,sizeof vis);
    		for(rint i=1;i<=n*2;++i){ // 枚举每个点作为根节点指向儿子,以保证每点入度不大于1
    			if(vis[i]) continue;
    			vec.clear();
    			S=0,T=0,ed_id=0;
    			dfs1(i,0);
    			dfs2(i,0);
    			rint cc=0;
    			if(!ed_id){
    				sort(vec.begin(),vec.end());
    				for(rint j=0;j<vec.size();++j){
    					if(vec[j]==vec[0]) ++cc;
    					else break;
    				}
    				(ans+=vec[0])%=M;
    				ans_cnt=1ll*ans_cnt*cc%M;
    			}
    			else{
    				const rint opt=ed_id&1;
    				if(f[S]+(!opt)==f[T]+opt) cc=2; // 注意不要'if(~~) f[S]++; else f[T]++; ',可能S==T
    				else cc=1;
    				(ans+=min(f[S]+(!opt),f[T]+opt))%=M;
    				ans_cnt=1ll*ans_cnt*cc%M;
    			}
    		}
    		printf("%d %d
    ",ans,ans_cnt);
    	}
    	return 0;
    }
    
  • 相关阅读:
    环境变量学习(二)Mac 可设置环境变量的位置
    环境变量学习(一)简介、查看
    shell学习(二)安装shell环境
    npm学习(十八)npm scripts 使用指南
    nodemon学习(二)实战
    nodemon学习(一)简介、安装、配置、使用
    Error: listen EADDRINUSE 127.0.0.1:8888错误解决
    树莓派创建wifi热点
    JavaScript中的数据类型转换
    Packstack 搭建 OpenStack 报 MariaDB 错误的处理
  • 原文地址:https://www.cnblogs.com/Lour688/p/13801157.html
Copyright © 2020-2023  润新知