一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍数。
例如:N = 8,数组A包括:2 5 6 3 18 7 11 19,可以选2 6,因为2 + 6 = 8,是8的倍数。
Input
第1行:1个数N,N为数组的长度,同时也是要求的倍数。(2 <= N <= 50000) 第2 - N + 1行:数组A的元素。(0 < A[i] <= 10^9)
OutPut
如果没有符合条件的组合,输出No Solution。 第1行:1个数S表示你所选择的数的数量。 第2 - S + 1行:每行1个数,对应你所选择的数。
Input示例
8 2 5 6 3 18 7 11 19
Output示例
2 2 6
解题思路:鸽巢原理的应用,有关鸽巢原理的内容可以参照百度百科。在本题中假设前i项和的模n的余数为ai,加入前1-n的每个余数均不同,则总共0->n-1,则我们只需要找到模0的前i项即可。如果存在至少两项i,j,i<j, sum[i]%n=sum[j]%n,则i到j之间的所有数的和是n的倍数。因此对于本题肯定存在解,我们便按照这种思路去寻找即可。
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <vector> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 50010; int arr[maxn]; ll sum[maxn]; int pos[maxn]; int n; int main() { bool ok = false; cin >> n; memset(pos, -1, sizeof(pos)); sum[0] = 0; for(int i = 1; i <= n; ++i) { scanf("%d", &arr[i]); if(ok) continue; sum[i] = (sum[i-1] + arr[i]) % n; if(sum[i] == 0) { ok = true; printf("%d\n", i); for(int j = 1; j <= i; ++j) { printf("%d\n", arr[j]); } continue; } if(pos[sum[i]] == -1) { pos[sum[i]] = i; } else { ok = true; printf("%d\n", i - pos[sum[i]]); for(int j = pos[sum[i]] + 1; j <= i; ++j) { printf("%d\n", arr[j]); } } } return 0; }