题解 Set
确实思路题
- 在 \(n\) 个非负整数中找出一个非空子集, 使得它的元素之和能被 \(n\) 整除,并输出方案
求出前缀和, 前缀和最多只有 \(n\) 个取值, 但是一共有 \(S[0], S[1]..S[N]\) 这 \(n+1\) 个值, 所以一定有某两个 \(S[i], S[j]\) 相等, 找出来再把 \(i\) 到 \(j\) 输出就可以了
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define fir first
#define sec second
#define make make_pair
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
namespace force{
bool vis[N];
pair<int, int> back[N];
int sta[N], top;
void dfs(int u) {
if (back[u].fir==-1) {printf("%d ", back[u].sec); return ;}
}
void solve() {
for (int i=1,t; i<=n; ++i) {
t=read()%n;
for (int j=n-1; ~j; --j) if (vis[j] && back[j].sec!=i && !vis[(j+t)%n]) {
vis[(j+t)%n]=1;
back[(j+t)%n]=make(j, i);
}
if (!vis[t%n]) vis[t%n]=1, back[t%n]=make(-1, i);
if (vis[0]) break;
}
// cout<<"pos1"<<endl;
if (!vis[0]) {puts("-1"); exit(0);}
int now=0;
while (1) {
// printf("%d ", back[now].sec);
sta[++top]=back[now].sec;
if (back[now].fir==-1) break;
now=back[now].fir;
}
printf("%d\n", top);
for (int i=1; i<=top; ++i) printf("%d ", sta[i]);
printf("\n");
exit(0);
}
}
namespace task{
ll sum[N];
unordered_map<ll, int> mp;
void solve() {
for (int i=0; i<=n; ++i) {
if (i) sum[i]=(sum[i-1]+read())%n;
if (mp.find(sum[i])!=mp.end()) {
printf("%d\n", i-mp[sum[i]]);
for (int j=mp[sum[i]]+1; j<=i; ++j) printf("%d ", j);
printf("\n");
exit(0);
}
mp[sum[i]]=i;
}
}
}
signed main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
n=read();
// cout<<double(sizeof(force::back)+sizeof(force::sta)+sizeof(force::vis))/1024/1024<<endl;
// force::solve();
task::solve();
return 0;
}