**
Description:
给出n(n<=10000)个数,任选q其中几个数,使其和为n的倍数。
Input:
输入的第一行包含一个数字n,接下来的n行每一行包含一个给定集合中的一个数字。
Output:
如果你的程序决定找不到目标的数字集,它应该输出到单个数字0。否则,它应该在第一行中打印所选数字的数目,然后按任意顺序打印所选数字(每一行上的每一行)。如果有多个具有所需属性的数字集,那么只需输出一个。
分析:
题目是special judge,只要找到即可。设前k项和Sk表示a1+a2+……ak, 如果Sk是n的倍数,那就直接取Sk,否则S1-Sn % n分布在1 –(n-1)然后判断这些数能否整除n,如果能则输出下标,然后直接从第一个数开始依次输出即可,否则就根据抽屉原理 ( 把多于n个的物体放到n个抽屉里,则至少有一个抽屉里有>=2个以上的物体 )得: n个 sum【i】% n中,至少有两个是一样的。(因此,此题一定有解,不存在输出0的情况)如果找到,则说明sum[i] % n == sum[j] %n 即sum[j] - sum[i])%n==0。也就是 夹在 i j 之间的数的和是 n的倍数,只要依次将他们输出就可以了。
所用知识:抽屉原理(组合数学)
题解:
只需要算出S1、S2、……Sk ,然后对n取余,如果没有取余后为0的,按sum[j] - sum[i])% n ==0 的公式算出 i , j,然后输出i 到 j的元素即可。
程序思路:
- 用Node结构体存储节点信息,之后按题解思路编写代码
AC C++代码 (POJ):
//————————————————-
#include <iostream>
using namespace std;
#define MAX 10010
struct Node
{
int a; //当前元素取值
int sum;//前k项和
}node[MAX];
bool mod[MAX];//利用哈希表,快速找出数组中相同的取余
void print(size_t first, size_t last)
{
cout << last - first + 1 << endl;
for(size_t i(first);i<=last;++i)
cout << node[i].a << endl;
}
void memsetMod(size_t &n)
{
for (size_t i = 0; i < n; ++i)
mod[i] = false;
}
int main()
{
size_t n(0),i(0);
bool flag(false);
node[0].sum = 0;
while(cin>>n)
{
memsetMod(n);//初始化Mod数组
for(i = 1;i <= n;++i)
{
cin >> node[i].a;
if (flag) continue;//如果flag为true表示已经输出了结果,只需要把剩余数据接收就行,不需要再运算
node[i].sum = node[i].a + node[i-1].sum;
size_t modCopy = node[i].sum % n;//S[i] % n的余数
if (modCopy == 0){//如果刚好有n的倍数
print(1, i);//输出
flag = true;
}
else if (mod[modCopy]) {//利用哈希数组快速找出Mod数组中相同元素
print(modCopy + 1, i);
flag = true;
}
else mod[modCopy] = true;
}
}
return 0;
}