题目链接:
http://poj.org/problem?id=2356
题目大意:
给你N个正数的序列,从中找到连续的若干数,使得其和刚好是N的倍数。
解题思路:
典型的抽屉原理。
Sum[i]为序列中前i项的和。则有两种可能:
1.若有Sum[i]是N的倍数,则直接输出前i项。
2.如果没有任何的Sum[i]是N的倍数,则计算ri = Sum[i] % N。根据鸽巢原理,肯
定有Sum[i] % N == Sum[j] % N,i != j。则第 j 到第 i 项数的和即为N的倍数。
AC代码:
//未优化的代码,172ms
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int Sum[10010],A[10010];
int main()
{
int N;
while(~scanf("%d",&N))
{
memset(Sum,0,sizeof(Sum));
for(int i = 1; i <= N; ++i)
{
scanf("%d",&A[i]);
Sum[i] = (Sum[i-1] + A[i]) % N;
}
int Flag = 0;
for(int i = 1; i <= N; ++i)
{
if(Sum[i] % N == 0)
{
printf("%d\n",i);
for(int j = 1; j <= i; ++j)
printf("%d\n",A[j]);
Flag = 1;
}
else
{
for(int j = 1; j < i; ++j)
{
if(Sum[i] == Sum[j])
{
printf("%d\n",i-j);
for(int k = j+1; k <= i; ++k)
printf("%d\n",A[k]);
Flag = 1;
break;
}
}
}
if(Flag)
break;
}
}
return 0;
}
//优化后代码,0ms
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int Sum[10010],A[10010],Mod[10010];
int main()
{
int N,Left,Right;
while(~scanf("%d",&N))
{
memset(Mod,-1,sizeof(Mod));
memset(Sum,0,sizeof(Sum));
Mod[0] = 0;
for(int i = 1; i <= N; ++i)
{
scanf("%d",&A[i]);
Sum[i] = (Sum[i-1] + A[i]) % N;
if(Mod[Sum[i]] == -1)
{
Mod[Sum[i]] = i;
}
else
{
Left = Mod[Sum[i]];
Right = i;
}
}
printf("%d\n",Right-Left);
for(int i = Left + 1; i <= Right; ++i)
printf("%d\n",A[i]);
}
return 0;
}