鸽巢原理
如果把 >n 个的元素放入n个抽屉中,那么一定有一个抽屉有大于等于2的元素,故又称 “抽屉原理”
poj 2356
题意:
找到m个数字使得这m个数字相加为n的倍数
输出m,然后输出这m个数字
题解:
先使用前缀和 sum[]
如果sum[i]%n==0 那么就已经找到了,输出 i 和这 i 个数字就行了
如果sum[i]%n!=0 那么一定存在 sum[j]%n==sum[i]%n , 那么输出i到j之间的数字就行了
注:
我一开始想的时候感觉这个题解有一点点问题,因为这个题解写的是按照连续的数字,也就是求一个区间内的,而且我也没有写0的情况,但是AC了,然后想为什么没有0,为什么数字都在一个区间内?万一不是一个区间的呢?然后就发现其实是我并没有很好的理解鸽巢原理,虽然这个原理看上去很简单,而且看上去和这道题没什么大的联系,但是上面的问题都可以用鸽巢原理来解释。
鸽巢原理对这题的解释:
因为有n个 sum[i] ,所以在 [1,n-1] 的区间内必定最少有一个数字是由多个 sum[i]%n 的情况的。( 因为sum[i]%n==0 就是一种情况的解,所以区间内不包含0,因此区间是 [1,n-1] ),因此这题必定有解,最少其中一个解必定是连续的。
1 |
|
poj 3370
和上题一样的思路……就不多说了,直接上代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using namespace std;
const int N = 1e5 + 5;
int a[N],sum[N],mod[N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) return 0;
for(int i=1;i<=m;i++) mod[i]=-1;
for(int i=1;i<=m;i++) sum[i]=0;
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
sum[i]%=n;
}
for(int i=1;i<=m;i++){
if(sum[i]==0){
for(int j=1;j<=i;j++) printf("%d ",j);
break;
}
else{
if(mod[sum[i]]!=-1){
for(int j=mod[sum[i]]+1;j<=i;j++) printf("%d ",j);
break;
}
}
mod[sum[i]]=i;
}
printf("\n");
}
return 0;
}