POJ 2356 Find a multiple

**

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结构体存储节点信息,之后按题解思路编写代码
POJ 2356 Find a multiple_第1张图片

AC C++代码 (POJ):
//————————————————-

#include 
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;
}

你可能感兴趣的:(poj,<组合数学>)