abcdeffa's Blog

当局者迷,旁观者清。

0%

GMOJ S3783 【签到题】

Description

给你一个数 $n$ 和 $n$ 个数 $a_1$ ~ $a_n$ ,现在请你求出这 $n$ 个数的一个非空子集,使得这个子集中的数的和能被 $n$ 整除,无解输出 -1 ,共有 $T$ 组数据。

下文将用 $|x|$ 来表示 $x$ 的绝对值。

Solution

设 $s_i$ 表示 $(\sum_{j = 1} ^ i a_i) \mod n$ ,那么 $s_i$ 的取值范围为 $[0, n)$ 。

所以我们可以用鸽巢原理证明出在 $s_1$ ~ $s_n$ 中至少有两个是相同的。

因此至少存在一段连续的数满足要求。

所以问题就被转化为了在原序列中找出连续的一段,使它的和能够被 $n$ 整除。

前缀和 即可解决。

时间复杂度 $O(Tn)$ 。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <cstdio>
#include <cstring>
#define maxN 200010
long long cnt[maxN], su[maxN], a[maxN];
long long min (long long x, long long y)
{
return x < y ? x : y;
}
long long max (long long x, long long y)
{
return x > y ? x : y;
}
int main ()
{
long long T = 0;
scanf("%lld", &T);
while(T--)
{
memset(cnt, 0, sizeof(cnt));
long long n = 0;
scanf("%lld", &n);
su[0] = 0;
for(long long i = 1;i <= n; i++)
{
scanf("%lld", &a[i]);
su[i] = su[i - 1] + a[i];
su[i] %= n;
}
long long mi = 2147483647;
long long ma = -2147483647;
for(long long i = 0;i <= n; i++)
{
mi = min(mi, su[i]);
ma = max(ma, su[i]);
}
for(long long i = 0;i <= n; i++)
{
su[i] -= mi;
}
for(long long i = 0;i <= n; i++)
{
if(!cnt[su[i]])
{
cnt[su[i]] = i + 1;
}
else
{
printf("%lld\n", i - cnt[su[i]] + 1);
for(long long j = cnt[su[i]];j <= i; j++)
{
printf("%lld ", a[j]);
}
printf("\n");
break;
}
}
}
return 0;
}