版权声明:本人原创,未经许可,不得转载 https://blog.csdn.net/qq_42505741/article/details/83276537
题目:
一个长度为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 < Aii <= 10^9)
Output
如果没有符合条件的组合,输出No Solution。
第1行:1个数S表示你所选择的数的数量。
第2 - S + 1行:每行1个数,对应你所选择的数。
Sample Input
8
2
5
6
3
18
7
11
19
Sample Output
2
2
6
解题报告:前缀和的取余运算,不得不说自己刚上来是想写dfs的,数据范围不允许,这道题目是惯性思维了,因为上周做过的一道题目让自己的思维卡死了,忘记了夏季学期学长出的那道题目了,本质是相同的,自己死在了思维固化了。。
其实前缀和之后对N取余,咱们只有0--N-1这N种情况,所以要么有0存在,要么就有相同的数字,所以不存在无解的情况。
咱们只有两种情况需要判断,就是1 从0-i 是取余相同的 或者是l - r 是相同的就可以了。
ac代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=50005;
int n;
ll num[maxn];
ll sum[maxn];
ll pos[maxn];
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(sum,0,sizeof(sum));
memset(pos,0,sizeof(pos));
int l,r;
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
sum[0]=0;
for(int i=1;i<=n;i++)
{
sum[i]=(sum[i-1]+num[i])%n;
if(sum[i]==0)
{
l=1;
r=i;
break;
}
else if(pos[sum[i]]!=0)
{
l=pos[sum[i]]+1;
r=i;
break;
}
pos[sum[i]]=i;
}
printf("%d\n",r-l+1);
for(int i=l;i<=r;i++)
printf("%d\n",num[i]);
}
}