51nod 1103 N的倍数

题目链接: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;
} 
原文地址:https://www.cnblogs.com/elisa02/p/12827064.html