题解:CF1270G Subset with Zero Sum

Luogu CF

考虑将 \(i-n\le a_i\le i-1\) 的两个 \(i\) 转化成一个,有:

\[1\le i-a_i\le n \]

\(b_i=i-a_i\),则因为 \(\sum_{i\in S}a_i=0\),所以 \(\sum_{i\in S}(i-b_i)=0\)。发现 \(i\)\(b_i\) 的范围是一样的,所以当当前的和是 \(i-b_i\) 的时候,我们可以加上 \(b_i-b_{b_i}\),使得和变为 \(i-b_{b_i}\),如此循环,只要又跳回到最初的 \(i\) 也就找出了一组解。

那么这个东西很像图论,建出 \(i\to b_i\) 的边,只要找到一个环即可,而且因为每个点的出度皆为 \(1\),所以一定存在环。

Code:

#include<iostream>
#include<queue>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=1e6+5;
int ab[maxn],ind[maxn],ans[maxn],tot;
bool vis[maxn];
queue<int> q;
inline void dfs(int cur){
	if(vis[cur])return;
	vis[cur]=true;
	ans[++tot]=cur;
	dfs(ab[cur]);
}
int main(){
	int it;
	cin>>it;
	while(it--){
		int in;
		scanf("%d",&in);
		rep(v1,1,in){
			vis[v1]=ind[v1]=0;
			int ia;
			scanf("%d",&ia);
			ab[v1]=v1-ia; 
		}
		rep(v1,1,in)ind[ab[v1]]++;
		rep(v1,1,in)if(!ind[v1])q.push(v1);
		while(!q.empty()){
			int cur=q.front();
			q.pop();
			if(!(--ind[ab[cur]]))q.push(ab[cur]);
		}
		tot=0;
		rep(v1,1,in)if(ind[v1]){
			dfs(v1);
			break;
		}
		printf("%d\n",tot);
		rep(v1,1,tot)printf("%d%c",ans[v1],v1!=tot?' ':'\n');
	}
	return 0;
}
posted @ 2025-07-21 15:03  FugiPig  阅读(10)  评论(0)    收藏  举报