题目
Description
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).
Input
The first line of the input contains the single number N. Each of next N lines contains one number from the given set.
Output
In case your program decides that the target set of numbers can not be found it should print to the output the single number 0. Otherwise it should print the number of the chosen numbers in the first line followed by the chosen numbers themselves (on a separate line each) in arbitrary order.
If there are more than one set of numbers with required properties you should print to the output only one (preferably your favorite) of them.
Sample Input
5
1
2
3
4
1
Sample Output
2
2
3
也就是说,在n个数里取一些数使它们的和是n的倍数,输出取的数的个数以及每个数.如果无法取出则输出0.
题解
我们写过指数暴力,打过搜索,因为数据范围加老爷机跪掉了.我不得不看了看题解.
确实精彩.我们对数列求前缀和,如果前i个的和对n取模为0,则直接输出1-i的数,否则因为前缀和取模有n个值,但只有n-1种可能(没有0),所以必然存在2个前缀和是相同的,直接输出这两个位置之间的所有数即可.小学学的抽屉原理,到这里就忘了.
#include<cstdio>
using namespace std;
const int boss=1e4;
int a[boss+10],s[boss+10],vis[boss+10],n;//vis表示对n取模的值.
int main()
{
int i;
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&a[i]),s[i]=s[i-1]+a[i];
vis[0]=1;//把0标记一下
for (i=1;i<=n;i++)
{
if (vis[s[i]%n])
{
int k=vis[s[i]%n];
printf("%d\n",i-k+1);
for (int j=k;j<=i;j++) printf("%d\n",a[j]);
return 0;
}
vis[s[i]%n]=i+1;
}
}//哈哈哈哈
本文介绍了一个经典的算法问题:从N个自然数中选取若干数,使其和为N的倍数。通过使用前缀和及抽屉原理,文章提供了一种高效解法,并附带完整的C++代码实现。

275

被折叠的 条评论
为什么被折叠?



