Description
一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍数。
例如:N = 8,数组A包括:2 5 6 3 18 7 11 19,可以选2 6,因为2 + 6 = 8,是8的倍数。
先欣赏一下两位大佬的代码
前缀和:https://blog.csdn.net/qq_38735931/article/details/81590452?utm_source=blogxgwz1
抽屉原理:https://blog.csdn.net/dingchenxixi/article/details/52459001
思路:
用一个sum数组记录前缀和,
先看简单的:想想如何存在一个i,sum[i]%n==0,是不是以为这前i个数的和是n的倍数,也就满足题目的要求,输出即可;
下面就是麻烦一点的:假设所有的sum[i]都不符合上面的条件,那么现在sum[i]的取值范围是【1,n-1】,但是i是从【1,n】的,根据抽屉原理,肯定有i!=j, sum[i]==sum[j]存在,这样他们的差值,也就是前j个数减去前i个数的那些数的和(假设j>i),一定是等于0的,也满足咱们题目的条件。
如果细心看的话,你是肯定可以看懂的。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int a[50005],sum[50005],book[50005];
int n,i,j;
scanf("%d",&n);
memset(a,0,sizeof(a));
memset(book,0,sizeof(book));
memset(sum,0,sizeof(sum));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=(sum[i-1]+a[i])%n;
}
for(i=1;i<=n;i++)
{
if(!sum[i])
{
printf("%d\n",i);
for(j=1;j<=i;j++)
printf("%d\n",a[j]);
return 0;
}
if(book[sum[i]]!=0)//如果前面有一个sum[]等于现在的sum[i]
{
printf("%d\n",i-book[sum[i]]);
for(j=book[sum[i]]+1;j<=i;j++)
{
printf("%d\n",a[j]);
}
return 0;
}
book[sum[i]]=i;//方便记录某个sum[i]出现位置的下标
}
// return 0;
}