题解:CF1270G Subset with Zero Sum
考虑将 \(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;
}

浙公网安备 33010602011771号