题目链接:http://poj.org/problem?id=2356
The input contains N natural (i.e. positive integer) numbers ( N <= 10000 ). Each of that numbers is not greater than 15000. This numbers are not necessarily different (so it may happen that two or more of them will be equal). Your task is to choose a few of given numbers ( 1 <= few <= N ) so that the sum of chosen numbers is multiple for N (i.e. N * k = (sum of chosen numbers) for some natural number k).
输入N(N <= 10000)个正整数。每个数不大于15000。这些数(this真是醉了)不是必须不同的(所以两个或多个数相同的是可能发生的)。你是任务是从这些书中选择一些数使得他们的和为N的倍数。SJ。
以前做过类似的题目是:给你n(n <= 20)个数,找一些书的和正好是等于某一个数。不同是这个需要找倍数。
学习了。。鸽巢原理。需要学习资料的狂戳->http://pan.baidu.com/s/1c0hFjKc
一个大部分用在存在性问题上的原理。。
对于该问题,我们把前余数作为巢。前n项和的余数为鸽子//貌似这种抽象不太正确。。
直接解释一下可行性吧。我们知道根据鸽巢原理这样的序列是一定存在的。。
对于n个数的前n项和肯定有0 - (n - 1) 个余数。如果出现前i项和余数为0了,那么1 - i就肯定是n的一个倍数。。如果前n项和没有为0的余数,那么根据鸽巢原理肯定会存在两个余数相同,也就意味着肯定会存在。。仔细想想为什么??
所以,我们只需要找到一个前n项和的余数为0,或者两个余数相等的位置。。。- - 。吊炸天。。
Code:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N = 1e4 + 5;
int a[N];
int mod[N];
int main()
{
int n;
while(~scanf("%d", &n)){
for(int i = 1; i <= n; i ++){
scanf("%d", &a[i]);
}
memset(mod, -1, sizeof(mod));
int sum = 0;
int ansx = -1, ansy = -1;
for(int i = 1; i <= n; i ++){
sum = (sum + a[i]) % n;
if(sum == 0){
ansx = 1; ansy = i;
break;
}
else {
if(mod[sum] != -1){
ansx = mod[sum] + 1; ansy = i;
break;
}
mod[sum] = i;
}
}
printf("%d\n", ansy - ansx + 1);
for(int i = ansx; i <= ansy; i ++){
printf("%d%c", a[i], i == ansy ? '\n' : ' ');
}
}
return 0;
}
------>
又学习了。。。- -