鸽巢原理又叫抽屉原理,百度百科的定义是:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面至少放两个苹果。这一现象就是我们所说的“抽屉原理”。
题意:从n个数中选出几个数的和是n的倍数。
因为给定的是n个数,所以结论是一定存在。证明如下:
用sum[k]表示前k个数的和,假设不存在,那么sum[k] % n一定在1到(n-1)之间,其中k为(1~n),那么它的余数至少有两个数是相等的。因为鸽巢原理n个苹果放到n-1个抽屉里,假设sum[i] % n == sum[j] % n, 那么sum[j] - sum[i]就一定可以被n整除。与假设矛盾。所以一定存在。
这个题的具体做法就是,先找sum[1]~sum[n]有没有能被n整除的,如果有的话,直接找到了。没有的话继续把没个数的余数保存下来,那么下次碰见和这个数余数相同的话,那么一定可以被n整除。代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 10010; int sum[maxn]; int b[maxn]; int main() { int n; while (~scanf("%d", &n)) { int a; for (int i = 1; i <= n; i++) { scanf("%d", &a); sum[i] = sum[i - 1] + a; } for (int i = 1; i <= n; i++) { if (sum[i] % n == 0) { printf("%d ", i); for (int j = 1; j <= i; j++) printf("%d ", sum[j] - sum[j - 1]); break; } if (b[sum[i] % n] != 0) { printf("%d ", i - b[sum[i] % n]); for (int j = b[sum[i] % n] + 1; j <= i; j++) printf("%d ", sum[j] - sum[j - 1]); break; } else b[sum[i] % n] = i; } } return 0; }
这个题和上一个题基本上一样,就是模c而已,正好c又是小于等于n的,所以满足鸽巢定理,wa了好久,,,发现用long long
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100010; typedef long long ll; ll sum[maxn] = {0}; int b[maxn]; int main() { int n, c; while (~scanf("%d %d", &c, &n) && (n + c)) { int a; for (int i = 1; i <= n; i++) { scanf("%d", &a); sum[i] = sum[i - 1] + a; } memset(b, 0, sizeof(b)); for (int i = 1; i <= n; i++) { if (sum[i] % c == 0) { for (int j = 1; j < i; j++) printf("%d ", j); printf("%d ", i); break; } else if (b[sum[i] % c] != 0) { for (int j = b[sum[i] % c] + 1; j < i; j++) printf("%d ", j); printf("%d ", i); break; } else b[sum[i] % c] = i; } } return 0; }