【51nod 1103】【N的倍数】(前缀和取余)

版权声明:本人原创,未经许可,不得转载 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]);	
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42505741/article/details/83276537