1. 程式人生 > >【51nod 1103】【N的倍數】(字首和取餘)

【51nod 1103】【N的倍數】(字首和取餘)

題目:

一個長度為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]);	
	}
}