版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AgoniAngel/article/details/51956623
基本原理: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,证毕。
题意:给出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;
}
}
}
}