题目链接:http://class.51nod.com/Challenge/Problem.html#problemId=1103
一、前言
这道题是一道特判题。只要输出符合结果即可,答案不唯一。
这里提供的是选择的数是连续的做法,如果要看不连续的做法请看别的文章。
二、题目描述
一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍数。
例如:N = 8,数组A包括:2 5 6 3 18 7 11 19,可以选2 6,因为2 + 6 = 8,是8的倍数。
输入
第1行:1个数N,N为数组的长度,同时也是要求的倍数。(2 <= N <= 50000)
第2 - N + 1行:数组A的元素。(0 < A[i] <= 10^9)
输出
如果没有符合条件的组合,输出No Solution。
第1行:1个数S表示你所选择的数的数量。
第2 - S + 1行:每行1个数,对应你所选择的数。
样例输入
8
2
5
6
3
18
7
11
19
样例输出
2
2
6
三、思路描述
满足题目的要求有两种情况。第一种情况是正常情况
第一种情况是:记录数组A的前缀和%n,一旦余数为0,则前面所有数的和% n = 0,满足题目的要求。一旦余数重复出现,即sum[i] %n=sum[ j]%n,则a[i+1]...a[j]的和% n = 0 如果n个前缀和中,存在sum[i]% n = 0的情况,则选取前i个数就是一个解。
第二种情况是:我们假设一个数%n的结果为x,这个数为q。如果在他后面又有一个数%n的结果为x,(这个x和前面的x的值一样)假设这个数为p。那么q后面那个数一直到p(不包含q,包含p)这些数字的和%n的结果也为0。我们多定义一个b数组记录:到第i个数的和%n之后的余数为i的(前缀和的位置)
四、代码
#include<cstdio> #include<iostream> using namespace std; int a[50010], sum[50010], n, b[50010]; int main(){ cin >> n; for(int i = 1;i <= n;i++){ cin >> a[i]; } for(int i = 1;i <= n;i++){ sum[i] = (sum[i-1] + a[i]) % n;//到目前为止的和%n的值,如果是n的倍数的话,说明%n=0 if(!sum[i]){//如果从头加到i这些数的和是n的倍数的话 cout << i << endl;//输出一共有i个数,因为从1开始循环 for(int j = 1;j <= i;j++){ cout << a[j] << endl;//输出这i个数 } return 0; } if(b[sum[i]]){//如果 cout << i - b[sum[i]] << endl;//输出选择了多少个数 //不能从第一次出现余数x的开始是因为前面没有出现过x所以只能从第一次出现x的后面那个数开始 for(int j = b[sum[i]]+1;j <= i;j++){//输出这些在x后面(不包含第一次出现的x) //并且在x第二次出现之前的这些数(包含第二次出现的x) cout << a[j] << endl; } return 0; } b[sum[i]] = i;//b数组记录的是到第i个数的和%n之后的余数为i的(前缀和的位置) } return 0; }