题解:CF1270G
给出n个整数a1a2⋯an,对于所有的1≤i≤n满足i−n≤ai≤i−1。找出这些整数的非空子集,满足元素和为0。根据题目,一定存在子集满足条件。如果有多个满足条件的子集,输出任意一个。
题面
Subset with Zero Sum
给出 n n n 个整数 a 1 , a 2 , ⋯ , a n a _ 1 , a _ 2 , \cdots , a _ n a1,a2,⋯,an,对于所有的 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 满足 i − n ≤ a i ≤ i − 1 i - n \le a _ i \le i - 1 i−n≤ai≤i−1。
找出这些整数的非空子集,满足元素和为 0 0 0。根据题目,一定存在子集满足条件。如果有多个满足条件的子集,输出任意一个。
输入
每个测试包含多个测试用例。第一行是测试用例的数量 t t t( 1 ≤ t ≤ 10 6 1 \le t \le 10 ^ 6 1≤t≤106)。每个用例的输入格式如下。
每个用例的第一行包括一个单独的整数 n n n( 1 ≤ n ≤ 10 6 1 \le n \le 10 ^ 6 1≤n≤106)。
第二行包括 n n n 个整数 a 1 , a 2 , ⋯ , a n a _ 1 , a _ 2 , \cdots , a _ n a1,a2,⋯,an( i − n ≤ a i ≤ i − 1 i - n \le a _ i \le i - 1 i−n≤ai≤i−1)。
保证所有用例的 n n n 的总和不超过 10 6 10 ^ 6 106。
输出
对于每个测试用例,输出两行。
在第一行,输出 s s s( 1 ≤ s ≤ n 1 \le s \le n 1≤s≤n)表示子集中的元素个数。
在第二行,输出 s s s 个整数 i 1 , i 2 , ⋯ , i s i _ 1 , i _ 2 , \cdots , i _ s i1,i2,⋯,is( 1 ≤ i k ≤ n 1 \le i _ k \le n 1≤ik≤n)。所有整数不同,且 a i 1 + a i 2 + ⋯ + a i s = 0 a _ {i _ 1} + a _ {i _ 2} + \cdots + a _ {i _ s} = 0 ai1+ai2+⋯+ais=0。
思路
tag \text{tag} tag:graphs math
对“一定存在子集满足条件”的证明。
对 i − n ≤ a i ≤ i − 1 i - n \le a _ i \le i - 1 i−n≤ai≤i−1 进行移项变形,得 1 ≤ i − a i ≤ n 1 \le i - a _ i \le n 1≤i−ai≤n。又 i i i 的取值为 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n,且 a i a _ i ai 的下标取值也为 1 1 1 到 n n n,故若将 1 1 1 到 n n n 设为点, 1 ≤ i ≤ n 1 \le i \le n 1≤i≤n 的所有 i i i 向 i − a i i - a _ i i−ai 连有向边,则得到一个 n n n 个点, n n n 条边的有向图,每个点出度为 1 1 1。
这时容易发现,因为点数与边数相等,故图不可能为树,即图中存在一个环,那么由于收尾相连,所以环上点的编号和会与环上点的子节点的编号和相等,即 ∑ i = ∑ ( i − a i ) \sum i = \sum (i - a _ i) ∑i=∑(i−ai)。移项,得 ∑ a i = 0 \sum a _ i = 0 ∑ai=0。于是,环上点的编号集合即为答案集合。
图上找环的时间复杂度为 O ( n ) O(n) O(n)。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+5;
int a[maxn];
bool vis[maxn];
int cnt[maxn];
int n;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
vis[i]=0;
}
int now=1,all=1;
while(!vis[now]){
vis[now]=1,cnt[now]=all;
now-=a[now],all++;
}
cout<<all-cnt[now]<<"\n";
int x=now;
do{
cout<<x<<" ";
x=x-a[x];
}while(x!=now);
cout<<"\n";
}
signed main(){
ios::sync_with_stdio(0);
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
更多推荐


所有评论(0)