抽屉原理

poj 2356 Find a multiple 

抽屉原理典型应用:一个由n个数组成的数列 一定能找出若干个连续的数使它们之和能n整除。

解释:n个数记为a[1],a[2],...a[n].设置一个数组sum,其存储信息为sum[i] = a[1] + a[2] + ...a[i];

情况一:存在一个k(1 <= k <= n),使得sum[k] % n == 0,那么就得证;

情况二:对于任意的k(1 <= k <= n),都有sum[k] % n != 0。 那么 对于n个sum数组的元素将会得到n个余数(即sum[k] % n且这些余数大于0且小于n)。这样对于n个余数(1 <= 余数 <= n-1),我们一定可以找到两个相等的余数,且它们对应sum数组中的start和end元素,使得(sum[end] - sum[start]%n==0。得证。

#include <cstdio>

#include <cstring>

#define MAX 10000+10

using namespace std;

int a[MAX], sum[MAX], vis[MAX];

int main()

{

int n, i, j;

int start, end;//start记录连续数列第一个数的位置 end记录最后一个 数的位置

int exist;//判断是否已经找到重复余数

int mark;//记录重复的余数  

while(scanf("%d", &n) != EOF)

{

memset(vis, 0, sizeof(vis));

memset(sum, 0, sizeof(sum));

exist = 0; mark = 0;

start = end = 0;

for(i = 1; i <= n; i++)

{

scanf("%d", &a[i]);

if(exist)//已经找到

continue;

sum[i] += a[i] + sum[i-1];

if(sum[i]%n == 0)//直接能被n整除

{

exist = 1;

start = 1;

    end = i;

continue;

}

if(vis[sum[i]%n]) //余数已经出现过

{

exist = 1;

mark = sum[i]%n;//记录重复余数

end = i;//记录结束位置

continue;

}

else

vis[sum[i]%n] = 1;

}

if(start == 1)//起点从1开始的

{

printf("%d\n", end);

for(i = 1; i <= end; i++)

printf("%d\n", a[i]);

}

else//起点不是从1开始的

{

for(i = 1; i <= n; i++)

    {

    if(sum[i]%n == mark)//找到第一个出现重复余数的位置

    {

    start = i+1;//记录位置

    break;

    }

    }

    printf("%d\n", end-start+1);

    for(i = start; i <= end; i++)

    printf("%d\n", a[i]);

}

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值