首页 > 其他分享 >Lights

Lights

时间:2024-06-24 14:12:07浏览次数:3  
标签:int void dfs Lights MAXN ans loop

题目信息

题目链接

Luogu CF1907G

思路分析

如果我们把每一个关系都转化为一条无向边,则 \(n\) 个点会有 \(n\) 条边,并且每一个点的度数至少是 \(1\),所以是一颗基环树森林。我们分别看看每一个数。

一棵树一定会有一个环,首先环外树的决策方案是一定的,一定是将每一个权值为 \(1\) 的点上传到祖先上面,使得它们被一起消掉,最后上传到环上就行。

紧接着就是处理在环上的点就行。假设环上权值为 \(1\) 的点的编号为:\(a_1,a_2,\dots,a_n\)。

  1. 若 \(n\nmid2\)
    此时在环上的点不管怎样都不可能两两消掉。
  2. 若 \(n\mid2\)
    此时我们有两种选择:
    • \(a_1\Leftrightarrow a_2,a_3\Leftrightarrow a_4,\dots,a_{n-1}\Leftrightarrow a_n\)。
    • \(a_2\Leftrightarrow a_3,a_4\Leftrightarrow a_5,\dots,a_n\Leftrightarrow a_1\)。
      我们只需要在这两种取最有情况就行了。

代码

#include<bits/stdc++.h>
using namespace std;
#pragma G++ optimize(1)
#pragma G++ optimize(2)
#pragma G++ optimize(3)
void read(int &x){
	x = 0;int p = 1;char ch;
	do{
		ch = getchar();
		if(ch=='-') p = -1;
	}while(!isdigit(ch));
	while(isdigit(ch)){
		x*=10;
		x+=ch-'0';
		ch = getchar();
	}
	x*=p;
}
void read(char &x){
    x = getchar();
    while(x==' '||x=='\n'||x=='\r') x = getchar();
}
void write(char x){
    putchar(x);
}
void write(int k){
	if(k<0) putchar('-');
	k = abs(k);
	stack<int> num;
	do{
		num.push(k%10);
		k/=10;
	}while(k);
	while(!num.empty()){
		putchar(num.top()+48);
        num.pop();
	}
}
const int MAXN = 2e5+10;
int T,n,loop1[MAXN],loop2[MAXN],floop1[MAXN],floop2[MAXN];
//graph
struct graph{
    struct EDGE{int x,y,nxt,from;}edge[MAXN];
    int h[MAXN],cnt;
    void new_edge(int x,int y,int from){
        edge[++cnt] = {x,y,h[x],from};
        h[x] = cnt;
    }
}v,tree;
//Topo
int inde[MAXN];
bitset<MAXN> loop,is;
void Topo(){
    queue<int> topo;
    for(int i = 1;i<=n;i++) if(!inde[i]) topo.push(i);
    while(!topo.empty()){
		int tmp = topo.front();topo.pop();loop[tmp] = 0;
		for(int pppi=v.h[tmp],i;pppi,i=v.edge[pppi].y;pppi=v.edge[pppi].nxt) 
			if(!(--inde[i])) topo.push(i);
	}
//	cout << loop[1] << " " << loop[2] << " " << loop[3] << " " << loop[4] << " " << loop[5] << endl;
}
void new_graph(){
    for(int i = 1;i<=n;i++){
        for(int pppj = v.h[i];pppj;pppj = v.edge[pppj].nxt){
            int j = v.edge[pppj].y;
            if(!loop[j]) tree.new_edge(i,j,v.edge[pppj].from);
            else if(!loop1[i]) loop1[i]=j,floop1[i]=v.edge[pppj].from;
            else loop2[i] = j,floop2[i]=v.edge[pppj].from;
        }
    }
}
//DP
vector<int> ans;
int dfs(int k,int fath){
    int sum = is[k];
    for(int pppp = tree.h[k];pppp;pppp = tree.edge[pppp].nxt){
        int i = tree.edge[pppp].y;
        if(i==fath) continue;
        int p = dfs(i,k);
        sum += p;
        if(p) ans.push_back(tree.edge[pppp].from);
    }
    return sum%2;
}
bitset<MAXN> vis;
int dfs_loop(int k,int from,int fath,vector<int> &ans){
    int sum = is[k];vis[k] = 1;int q = 0;
	if(k==from) return sum;
    if(loop1[k]!=fath){
		q++;
        int p = dfs_loop(loop1[k],from,k,ans);
        sum += p;
        if(p) ans.push_back(floop1[k]);
    }else if(loop2[k]!=fath){
		q++;
        int p = dfs_loop(loop2[k],from,k,ans);
        sum += p;
        if(p) ans.push_back(floop2[k]);
    }
	if(!q){
		int p = dfs_loop(loop1[k],from,k,ans);
		sum += p;
		if(p) ans.push_back(floop1[k]);
	}
    return sum%2;
}
//Normal
void clear(){
    vis.reset();loop.reset();ans.clear();
    v.cnt = tree.cnt = 0;
    for(int i = 1;i<=n;i++){
		v.h[i] = 0;tree.h[i] = 0;
        inde[i] = 0;
        loop[i] = 1;
        loop1[i] = 0;
        loop2[i] = 0;
		floop1[i] = 0;
		floop2[i] = 0;
    }
}
signed main(){
    read(T);
    while(T--){
//		if(T==9888){
//			cin >> n;cout << n;
//			string x;
//			cin >> x;cout << x << endl;
//			for(int i = 1;i<=n;i++){
//				int x;
//				cin >>x ;
//				cout << x << " ";
//			}
//			return 0;
//		}
		read(n);
		clear();
        for(int i = 1;i<=n;i++){
            char k;
            read(k);
            is.set(i,k-'0');
        }
        for(int i = 1;i<=n;i++){
            int x;
            read(x);
			inde[x]++;
            v.new_edge(i,x,i);
            v.new_edge(x,i,i);
        }
        Topo();new_graph();
//		for(int pppp = tree.h[9],i;pppp,i=tree.edge[pppp].y;pppp=tree.edge[pppp].nxt) cout << i << endl;
        for(int i = 1;i<=n;i++){
            if(loop[i]){
                int sum = is[i];
                for(int pppj=tree.h[i],j;pppj,j=tree.edge[pppj].y;pppj=tree.edge[pppj].nxt){
                    int p = dfs(j,i);
                    sum += p;
                    if(p) ans.push_back(tree.edge[pppj].from);
                }
                is.set(i,sum%2);
            }
        }
		bool fg = 1;
        for(int i = 1;i<=n;i++){
            if(loop[i]&&!vis[i]&&is[i]){
                vector<int> ans1,ans2;
                int k = dfs_loop(loop1[i],i,i,ans1);
                dfs_loop(loop2[i],i,i,ans2);
				if(k&1) fg  = 0;
                if(ans1.size()>ans2.size()) swap(ans1,ans2);
                for(int i:ans1) ans.push_back(i);
            }
        }
		if(fg){
        write((int)ans.size());write('\n');
        for(int i:ans) write(i),write(' ');
        write('\n');
		}else puts("-1");
    }
    return 0;
}

tag

Codeforces
图论基环树拓扑排序DFS

标签:int,void,dfs,Lights,MAXN,ans,loop
From: https://www.cnblogs.com/gutongxing/p/18264913

相关文章

  • P6261 [ICPC2019 WF] Traffic Blights 题解
    思路考虑题目要求的是什么。假设\(p_i\)代表通过前\(i\)个红绿灯的概率。那么我们的答案即为\(p_i-p_{i-1}\)。不妨设\(w_i=r_i+g_i\)。我们的限制条件类似:\[t\not\equiva_i\pmodw_i\]那么所有红绿灯会形成周期\(lcm(w_1,w_2,\cdots,w_n)\)。由于\(2019!\)肯......
  • [题解]CF1907G Lights
    CF1907GLights我们可以把灯抽象成节点,而开关抽象成无向边(重边算作\(1\)条)。显然每个连通块要么是一棵树,要么是一棵基环树。对于基环树,我们把它看做若干棵树处理,最后我们再考虑如何处理环。如下图,这是一棵树,黄色的点表示亮灯。我们选定任意一条边,可以改变子节点和父节点的状......
  • CF729B Spotlights 题解
    题目简述给出一个$n$行$m$列的$01$矩阵,定义每个点的价值为上下左右四个方向有$1$的方向数,求所有为$0$的点的价值和。题目分析我们首先可以考虑暴力,但是发现是不行的。于是我们考虑动态规划。设$dp_{i,j,0/1/2/3}$分别表示$(i,j)$这个点上方,左方,下方,右方是否有$......
  • CF241E Flights
    CF241EFlights边权转点权+差分约束显然图中不在\(1\)到\(n\)路径上的边是不会影响答案的,所以现在只考虑\(1\)到\(n\)路径上的边。然后就有重要性质,图中\(1\)到\(n\)的所有路径的航程相同可以转化为,对于每个在\(1\)到\(n\)某条路径上的\(u\),都有\(1\)到\(u......
  • 获取AWS lightsail Windows server RDP密码
    场景创建lightsail的linuxserver时已经生成SSHkey,建立Windows的实例(Instance)时,并未提示输入管理员密码。登录时,找密码登录,提示“DecipheryourpasswordYouusedthe"keyname"keywhenyoucreatedthisinstance.Seetheinstructionstodecipherthepasswordfromthe......
  • CF958F1 Lightsabers (easy) 题解
    题面。不好意思,当我看到\(1\len\le100\),\(1\lem\len\)的那一刻,我承认我心动了。题目没翻译,用翻译软件翻译了才看懂。思路依据题意直接模拟即可。这里我用了三层循环来模拟。第一层为\(len\),表示长度;第二层为\(from\),表示出发点,此时需要遍历的区间的终点\(to=from......
  • CF294C Shaass and Lights
    对于给定的\(m\)个点,将整个序列分为了\(m+1\)段,我们可以先将每一段看作同一个类型,同一个类型间不同的顺序看作同一种。那么显然,答案即为可重集的排列数。设\(\{S=n_1\cdota_1,n_2\cdota_2,...,n_k\cdota_k\}\)表示由\(n_i\)个\(a_i\)组成的集合。那么此集合的排......
  • G. Lights
    原题链接太巧妙了!!关键1:把开着的灯当成黑点看待关键二:如图更多细节请看代码code#include<bits/stdc++.h>usingnamespacestd;intto[100005];//代表会被我影响的灯,抽象成边voidsolve(){intn;intstate[100005]={0};//代表每个灯的状态int......
  • P9017 [USACO23JAN] Lights Off G 题解
    一次操作相当于把\(a\)异或上\(b\),修改开关的一位相当于将这一位异或上\(1\)。会发现一个很神奇的性质:初始开关对灯的影响和改变开关状态对灯的影响是独立的。而前者的影响是固定的,所以我们可以只考虑改变开关状态对灯的影响。假设一共需要\(k\)次操作能使所有灯关闭,如果我......
  • [CF958F3] Lightsabers (hard)
    题目链接对于一种元素\(v\),假设它在给出可重集合中出现了\(t\)次,那么容易把它表示成基础的生成函数形式:\(1+x+x^2+x^3+\dots+x^t\)。显然,把所有元素的生成函数卷一下就是答案。但是这样最坏情况为\(O(nm\logn)\)的,不能通过这道题。在思考优化方式时,容易想到启发式合并来优......