[关闭]
@LinKArftc 2015-08-17T15:54:41.000000Z 字数 1422 阅读 1834

鸽笼原理

数学 鸽笼原理


定理

a1,a2,a3...am是正整数序列,至少存在整数kr, 1 <= k < r <= m,使得ak+a(k+1)+...+ar是m的倍数。

几个推论

  1. m只鸽子,n个笼,则至少有一个鸽笼里有不少于[(m - 1) / n] + 1只鸽子。
  2. 若取n * (m - 1) + 1个球放进n个盒子,则至少有1个盒子有m个球。
  3. 若m1,m2,...mn是n个正整数,而且(m1 + m2 + ... + mn) / n > r - 1 则m1,m2,...mn中至少有一个数不小于r

应用

POJ 2356

题意

给 n 个数,问其中是否存在某些数的和是 n 的倍数,如果存在,输出任意一组数字总数和每个数,否则输出 0

思路

根据鸽笼原理,答案一定存在且是连续。先求前k(1 <= k <= n)个数的和sum[k],然后求sum[k]模除 n的值Mod[k],如果存在 Mod[k] == 0,则直接输出结果,如果不存在,因为 1 <= Mod[k] <= n - 1,所以一定存在 Mod[a] == Mod[b] (a < b),则a,b之间的数就是我们要求的结果

AC代码

  1. const int maxn = 10005;
  2. int num[maxn];
  3. int pre[maxn];
  4. void print(int pos) {
  5. printf("%d\n", pos);
  6. for (int i = 1; i <= pos; i ++) printf("%d\n", num[i]);
  7. }
  8. void print(int a, int b) {
  9. printf("%d\n", b - a);
  10. for (int i = a + 1; i <= b; i ++) printf("%d\n", num[i]);
  11. }
  12. int main() {
  13. int n;
  14. while (~scanf("%d", &n)) {
  15. bool flag = false;
  16. memset(pre, 0, sizeof(pre));
  17. int sum = 0, tmp, ans;
  18. for (int i = 1; i <= n; i ++) {
  19. scanf("%d", &num[i]);
  20. sum += num[i];
  21. tmp = sum % n;
  22. if (tmp == 0) {
  23. if (!flag) {
  24. print(i);
  25. flag = true;
  26. }
  27. } else {
  28. if (pre[tmp] && !flag) {
  29. print(pre[tmp], i);
  30. flag = true;
  31. } else pre[tmp] = i;
  32. }
  33. }
  34. }
  35. return 0;
  36. }

POJ 3370

题意

类似于上一题,给n个数求是否存在某些数的和是c的倍数,c是小于n的,注意这一题输出的数字下标,且sum会超int

思路

见上一题

AC代码

  1. const int maxn = 100005;
  2. int pre[maxn];
  3. int main() {
  4. int c, n;
  5. while (~scanf("%d %d", &c, &n)) {
  6. if (c == 0 && n == 0) break;
  7. ll sum = 0, cur, tmp;
  8. bool flag = false;
  9. memset(pre, 0, sizeof(pre));
  10. for (int i = 1; i <= n; i ++) {
  11. scanf("%lld", &cur);
  12. sum += cur;
  13. tmp = sum % c;
  14. if (tmp == 0) {
  15. if (!flag) {
  16. for (int j = 1; j <= i; j ++) printf("%d%c", j, j == i ? '\n' : ' ');
  17. flag = true;
  18. }
  19. } else {
  20. if (pre[tmp]) {
  21. if (!flag) {
  22. for (int j = pre[tmp] + 1; j <= i; j ++) printf("%d%c", j, j == i ? '\n' : ' ');
  23. flag = true;
  24. }
  25. } else pre[tmp] = i;
  26. }
  27. }
  28. }
  29. return 0;
  30. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注