抽屉原理简单应用 POJ 2356 POJ 3370
来源:互联网 发布:淘宝卖家网页制作 编辑:程序博客网 时间:2024/05/22 03:17
基本原理:k+1个物体放入k个盒子,一定至少有一个盒子有2个或更多的物体。
数学语言描述为:m(m>=1)个元素分成n个组,那么总有一个组至少含有元素个数为[ m/n ](向上取整)。
重要推论:设a1,a2,...,am是正整数的序列,则一定存在整数k和l,1<= k < l <=m,使得连续子序列和ak+a(k+1)+...+al是m的倍数。
证明:设Sk表示前k项和,
(1)若有一个Sk是m的倍数,则定理已得证;
(2)设在上面的序列中没有一个Si(1<=i<=m)是m的倍数,令ri=Si%m。
我们已知上面的所有项都非m的倍数,则ri(1<=i<=m)都不为0。
根据抽屉原理,这m个余数在[1,m-1]里取值至少存在一对rh,rk,满足rh=rk,即Sh=Sk mod m。
不妨设h>k,则 Sh-Sk=a(k+1)+a(k+2)+...+ah≡0 mod m,证毕。
POJ 2356
题意:给出n个数,从中取若干个数,使得这些数和为n的倍数。给出其中一种取法。因为只要给出其中一种方案就行,抽屉原理可以求出取出的数为连续的方案。
思路:直接应用推论。
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string>#include <vector>#include <cctype>#define mst(a,b) memset(a,b,sizeof(a))typedef long long LL;using namespace std;const int N = 10001;int a[N],sum[N],r[N];//r[i]表示余数为i的数的下标int main(){ //freopen("test.txt","r",stdin); int n; while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ r[i]=-1; scanf("%d",&a[i]); } if(a[0]%n==0){ printf("1\n%d\n",a[0]); continue; } sum[0]=a[0]; r[sum[0]%n]=0; for(int i=1;i<n;i++){ sum[i]=a[i]+sum[i-1]; if(sum[i]%n==0){ printf("%d\n",i+1); for(int j=0; j<=i; j++) printf("%d\n",a[j]); break; } if(r[sum[i]%n]==-1) r[sum[i]%n]=i; else { printf("%d\n",i-r[sum[i]%n]); for(int j=r[sum[i]%n]+1;j<=i;j++) printf("%d\n",a[j]); break; } } }}
POJ 3370
题意:与上一题不同之处在于取的一组数要整除的不是n,而是c,其中1<=c<=n。另外输出的是选出来的数的下标,不是数本身。
思路:根据推论的证明过程,我们完全可以进一步推出:对于任意1<=c<=n,都必然能找到一个连续子序列满足其和是c的倍数。
#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string>#include <vector>#include <cctype>#define mst(a,b) memset(a,b,sizeof(a))typedef long long LL;using namespace std;const int N = 100001;int a[N],r[N];LL sum[N];int main(){ //freopen("test.txt","r",stdin); int n,c; while(scanf("%d%d",&c,&n)&&(n||c)){ for(int i=0;i<n;i++){ r[i]=-1; scanf("%d",&a[i]); } if(a[0]%c==0){ printf("1\n"); continue; } sum[0]=a[0]; r[sum[0]%c]=0; for(int i=1;i<n;i++){ sum[i]=a[i]+sum[i-1]; if(sum[i]%c==0){ printf("1"); for(int j=1; j<=i; j++) printf(" %d",j+1); printf("\n"); break; } if(r[sum[i]%c]==-1) r[sum[i]%c]=i; else { printf("%d",r[sum[i]%c]+1+1); for(int j=r[sum[i]%c]+2;j<=i;j++) printf(" %d",j+1); printf("\n"); break; } } }}
0 0
- 抽屉原理简单应用 POJ 2356 POJ 3370
- poj 2356 简单抽屉原理
- poj 3370 抽屉原理
- poj 3370 抽屉原理
- poj 3370 抽屉原理
- poj 3370(抽屉原理)
- POJ 2356 抽屉原理
- POJ 2356 抽屉原理
- poj 3370 Halloween treats(抽屉原理)
- POJ 3370 Halloween treats(抽屉原理)
- POJ 3370 Halloween treats(抽屉原理)
- POJ 3370 Halloween treats(抽屉原理)
- POJ 3370 Halloween treats(抽屉原理)
- POJ 3370 Halloween treats(抽屉原理)
- poj 3370 Halloween treats 【抽屉原理】
- POJ 3370 Halloween treats(抽屉原理)
- poj 3370 Halloween treats <抽屉原理>
- POJ-3370 Halloween treats (抽屉原理)
- 关于对接rtx推送通知
- md5加密base64加密解密
- Android ListView 弹性滚动简单实现
- Android学习笔记032之数据存储—文件存储读取
- $x输出什么?
- 抽屉原理简单应用 POJ 2356 POJ 3370
- 第三届中国云计算用户大会笔记和心得
- Android初学之ViewPager
- 如何使用appverifier?
- Exception sending context initialized event to listener instance of class org.springframework.web.co
- Freescale android 4.4.2 平台工具链安装--技巧
- 阻塞与非阻塞-同步与异步
- Java泛型
- Android网络请求框架Retrofit使用详解