鸽巢原理 Poj3370&Hdu1808 + Poj2356 + Hdu 1205

来源:互联网 发布:python在ubuntu怎么用 编辑:程序博客网 时间:2024/05/18 12:39

2014-3-25 更新 :修正了Hdu1205的代码,貌似以前的版本过不了,少输出了回车。

Poj 的一个评论很有启发:http://poj.org/showmessage?message_id=171199

如果将读入的数据存入a[1], a[2],...,a[n];余数位置数组就赋初值为0即可
如果将读入的数据存入a[0], a[1],...,a[n-1];余数位置数组初值必须为-1,否则f[1]=0即可表示余数为1的出现在位置0,也可表示余数为一的没出现过,出现了双重含义


组合数学的知识,偶然碰到的题,于是把几道简单的都刷了。。

不知为什么网上的题解都把Poj2356写成2365……这就是以讹传讹么……

P.S. 2356也做了,是道计算几何水题,看别人的解题报告还学到了一个函数:


hypot

功 能: 计算直角三角形的斜边长
用 法: double hypot(double x, double y);

使用时需要定义<cmath>,其实自己写也不费事……


以下关于前两个题的分析转自:http://blog.csdn.net/new_c_yuer/article/details/6418662


    首先简单说一下鸽巢原理,就是有n+1个球,放在n个盒子中,那么至少有一个盒子有两个或更多的球。

    而这两道题正是运用了这个思想。先对数列求前N项和,有s1=a1,s2=a1+a2,

s3=a1+a2+a3,......,sn=a1+a2+a3+...+an。若其中有和可以整除m,那么即可得出答案,否则,所得的余数只会是1,2,...,n-1,因此,必存在至少两个数模除m后有相同余数r,即si=b*m+r,sj=c*m+r,则si-sj=(b-c)*m。则序列ai到aj的和即为所求。



我的代码:

Poj 3370 & Hdu 1808 Halloween treats

题意:给定n个数,从中选出连续的若干个,使得和为c的倍数,输出标号。多解时输出任意解。

#include <cstdio>#include <cstring>int data[100005];int remainder[100005];int c,n;int main (){    while (scanf("%d%d",&c,&n) && (c||n)){int i,s,e;memset(remainder,0,sizeof(remainder));for (i=1;i<=n;i++)scanf("%d",&data[i]);int sum=0;for (i=1;i<=n;i++){sum=(sum+data[i])%c;if (sum == 0){s=1;e=i;break;}else if (remainder[sum]){s=remainder[sum]+1;e=i;break;}elseremainder[sum]=i;}for (i=s;i<=e;i++)printf(i==e?"%d\n":"%d ",i);    }    return 0;   } 

Poj 2356 Find a multiple

题意:给定n个数,从中选出连续的若干个,使得和为n的倍数,按顺序输出这些数。多解时输出任意解。

#include <cstdio>#include <cstring>int data[10005];int remainder[10005];int main (){int n;    while (~scanf("%d",&n)){int i,s,e;memset(remainder,0,sizeof(remainder));for (i=1;i<=n;i++)scanf("%d",&data[i]);int sum=0;for (i=1;i<=n;i++){sum=(sum+data[i])%n;if (sum == 0){s=1;e=i;break;}else if (remainder[sum]){s=remainder[sum]+1;e=i;break;}elseremainder[sum]=i;}printf("%d\n",e-s+1);for (i=s;i<=e;i++)printf("%d\n",data[i]);    }    return 0;   }  

Hdu 1205 吃糖果
一开始没多想,就想了隔一个放一个,过了之后搜解题报告发现这题还挺深奥……
注意sum需要用长整型。
参见 http://ip96cns.blog.163.com/blog/static/17009519220111217501402/
#include <cstdio>int main (){int T;scanf ("%d",&T);while (T--){int n,temp,maxn=0;__int64 sum=0;scanf("%d",&n);for (int i=0;i<n;i++){scanf("%d",&temp);if (temp>maxn)maxn=temp;sum+=temp;}if (sum-maxn+1>=maxn)printf("Yes\n");elseprintf("No\n");}return 0;}



还有 Hdu 1029 不过这题解法比较多,会在下一篇文章中总结。

原创粉丝点击