首页 > 其他分享 >[题解]CF1907G Lights

[题解]CF1907G Lights

时间:2024-05-08 23:11:43浏览次数:15  
标签:sta 开关 int 题解 pos Lights CF1907G 节点 deg

CF1907G Lights

我们可以把灯抽象成节点,而开关抽象成无向边(重边算作\(1\)条)。

显然每个连通块要么是一棵树,要么是一棵基环树。

对于基环树,我们把它看做若干棵树处理,最后我们再考虑如何处理环。

如下图,这是一棵树,黄色的点表示亮灯。
image
我们选定任意一条边,可以改变子节点和父节点的状态。

那么对于每一棵树,我们的想法是把亮的灯转换到根节点上,这样才能在基环树的环上继续操作。

我们可以用拓扑排序解决。对于叶子节点,如果该点亮着灯,我们按下开关,改变自己和父节点的状态。这样此点已经熄灭,我们可以将其删掉。继续重复上述步骤,直到只剩下根节点。根节点可能亮也可能灭。

对整个图拓扑排序完,就只剩下若干个环了。对于每个环,我们进行如下考虑:
image

首先如果环上亮着的灯有奇数个,说明无论怎么操作都无法让所有灯都灭掉,输出\(-1\)即可。

如果有偶数个亮灯,如上图,有两种情况灭掉所有灯:

  • \(2\)到\(3\)之间所有开关(边)都按一遍,这样可以同时把\(2,3\)熄灭;再把\(5\)到\(7\)之间的所有开关都按一遍,同时把\(5,7\)熄灭。
  • 我们也可以错一下位,选择\(3\ -\ 5\)和\(7\ -\ 2\)熄灭。

因此对于每一个环,我们需要依次对上面两种情况按的开关数进行计数,哪种按开关次数(经过边的个数)最少就选哪种。

树上的操作\(+\)环上的操作\(=\)总操作。使用一个\(vector\)记录下结果,输出即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n,a[100010];
bool s[100010];
int deg[100010];
vector<int> ans;
queue<int> q;
void solve(){
	memset(deg,0,sizeof deg);
	ans.clear();
	cin>>n;
	for(int i=1;i<=n;i++){
		char c;
		cin>>c;
		s[i]=c-'0';
	}
	for(int i=1;i<=n;i++){
		cin>>a[i];
		deg[a[i]]++;
	}
	for(int i=1;i<=n;i++){
		if(deg[i]==0) q.push(i);
	}
	while(!q.empty()){
		int t=q.front();
		int r=a[t];
		q.pop();
		deg[r]--;
		if(s[t]){//上移标记,记录结果
			s[r]=!s[r];
			ans.emplace_back(t);
		}
		if(!deg[r]){//入度为0则入队列
			q.push(r);
		}
	}
	for(int i=1;i<=n;i++){
		if(deg[i]&&s[i]){
			vector<int> aa,bb;
			int pos=i;
			bool sta=0;
			while(deg[pos]){
				deg[pos]--;
				if(s[pos]) sta=!sta;
				if(sta) aa.push_back(pos);
				else bb.push_back(pos);
				pos=a[pos];
			}
			if(sta){
				cout<<"-1\n";
				return;
			}
			if(aa.size()<bb.size()){
				ans.insert(ans.end(),aa.begin(),aa.end());
			}else{
				ans.insert(ans.end(),bb.begin(),bb.end());
			}
		}
	}
	cout<<ans.size()<<"\n";
	for(auto i:ans) cout<<i<<" ";
	cout<<"\n";
}
int main(){
	cin>>t;
	while(t--) solve();
	return 0;
}

(代码有借鉴此文章 by _Ink

标签:sta,开关,int,题解,pos,Lights,CF1907G,节点,deg
From: https://www.cnblogs.com/Sinktank/p/18178454

相关文章

  • CodeForces 1967D Long Way to be Non-decreasing 题解
    题意简述yzh喜欢单调不降序列。她有一个序列\(a\),最初为\(a_1,\ldots,a_n\),其中每个元素都在\([1,m]\)内。她希望使序列变得单调不降,为此,她有一个序列$b_1\ldotsb_m$,每个元素也在\([1,m]\)内。她可以进行若干次操作,一次操作定义为:选择一个集合\(S\subseteq......
  • CF1967C题解
    CF1906D这里更容易进入且有翻译题意对于数组\(a\),有函数\(f(a)\),设数组\(s=f(a)\),则对于每一个\(s_i\),都有:\[s_i=\left(\sum^{i}_{j=(i\operatorname{\&}(i-1))+1}{a_j}\right)\]其中\(\&\)表示按位与运算。对于一个正整数\(k\),函数\(f^k(a)\)定义如......
  • P10429 [蓝桥杯 2024 省 B] 拔河 题解
    思路通过动态规划计算出所有连续子序列的力量值之和,并将其存储在一个数组中然后排序,遍历一遍数组,找到相邻两个力量值之和的差的绝对值的最小值,然后输出这个答案就行了。时间复杂度大概是\(O(n^2\logn)\)。来个python的代码defmin_power_diff(n,a):#计算所有连续子序列......
  • 「高精度乘法+高精度加法」P10425 [蓝桥杯 2024 省 B] R 格式 题解
    解题思路题意分析:将浮点数乘以\(2^n\);四舍五入到最接近的整数。根据题意将\(d\times2^n\)分解为\(d\times2\times2\times2\times2……\),因为\(d\)长度小于等于\(1024\),所以可以使用高精度乘法的算法来实现一个小数乘以一个大于\(0\)的整数时,小数点位数本身不会......
  • [COCI2022-2023#1] Berilij 题解
    SolutionP9030[COCI2022-2023#1]Berilij本题解转载翻译自官方题解:COCI2022/2023CONTEST1Part1让我们定义图形\(G\),顶点代表飞船,边代表两艘飞船外部接触的情况。此外,让边的边权成为它所连接的圆之间的距离。现在的任务等同于为顶点找到非负值,使得每条边所连接的两个顶......
  • cuda使用时Could not locate zlibwapi.dll 问题解释和解决
    第一次配置cuda环境,python环境训练模型时,可能遇到Couldnotlocatezlibwapi.dll.Pleasemakesureitisinyourlibrarypath! 原因就是window系统里没有zlibwapi.dll.,与cuda没关系,cuda只是依赖它。安装某些软件时可能会自动把这个动态库安装到系统的某个path路径下,比如......
  • ICPC2024 武汉邀请赛 题解
    2024ICPCNationalInvitationalCollegiateProgrammingContest,WuhanSiteB-CountlessMeSolution显然,只能执行\(n\)次操作是没用的条件我们只需要把和\(sum\)分给\(n\)个数,使得\(n\)个数的或和最小即可从高到低考虑每一位,假设此时枚举到第\(i\)位如果这一......
  • 【题解】爬山 蓝桥杯2024省B
    题目链接:P10429[蓝桥杯2024省B]拔河[蓝桥杯2024省B]拔河题目描述小明是学校里的一名老师,他带的班级共有\(n\)名同学,第\(i\)名同学力量值为\(a_i\)。在闲暇之余,小明决定在班级里组织一场拔河比赛。为了保证比赛的双方实力尽可能相近,需要在这\(n\)名同学中挑选......
  • XMOJ 四月月赛 T3 旅行 题解
    我们首先尝试挖掘这个分组的性质。我们发现,我们可以把在同一个组的夫妻和不在同一个组的夫妻分开来处理。这里,分开之后我们只需要让一种情况有顺序,另外一种不能有顺序。如果两个没有顺序/有顺序的序列合并,一定会出现漏算/多算。所以为了方便,我们可以把第二种情况看作有顺......
  • [题解]P1757 通天之分组背包
    P1757通天之分组背包分组背包模板题。总共\(s\)组,每组最多取一个物品,实际上就是一个物品总数为\(s\)的背包。for(inti=1;i<=s;i++){//枚举组 for(intj=1;j<=n[i];j++){//枚举每组的元素 for(intk=1;k<=m;k++){//枚举背包大小 f[i][k]=max(f[i][k],f[i-1][k]); if(......