鸽巢原理入门
题目传送门:点击打开链接
Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 7055 | Accepted: 3086 | Special Judge |
Description
Input
Output
Sample Input
5 1 2 3 4 1
Sample Output
2 2 3
Source
先引入鸽巢原理概念:
鸽巢原理,又名狄利克雷抽屉原理、鸽巢原理。
其中一种简单的表述法为:若有n个笼子和n+1只鸽子,所有的鸽子都被关在鸽笼里,那么至少有一个笼子有至少2只鸽子。
百度鸽巢原理视频,竟然所有的都是为了小学生准备的,真是欲哭无泪!
本题的意思很简单,给n个数,从中任意选出若干个数,求和,要求其满足是n的倍数。这里说明一下,任意n个数是必然能够找的到若干个数求其和满足整除n。证明:从第一个数开始依次求和保存于Sk中,那么S1到Sn mod n在1-n之间,根据鸽巢原理得知必然有两个Si、Sj mod n的结果相同,则(Sj%n)==(Si%n)==>(Sj-Si)%n == 0即可求出题中所述结果。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <algorithm> #include <stack> #include <set> using namespace std; typedef long long int LL ; int a[10010]; LL s[10010]; //求和数组结果 int b[10010]; //保存其和余数 int c[10010]; //标记数组 int main() { int n; cin >> n; memset(a, 0, sizeof(a)); for (int i = 1; i<=n; i++) cin >> a[i]; memset(s, 0, sizeof(s)); for (int i = 1; i<=n; i++) { //扫描求和,若遇到满足答案则结束 s[i] = s[i-1] + a[i]; if (s[i] %n == 0) { cout << i<< endl; for (int j = 1; j<=i; j++) cout << a[j]<< endl; return 0; } //cout << s[i]<< endl; } //cout << endl; memset(b, 0, sizeof(b)); memset(c, 0, sizeof(c)); int flag = 1; int i; for (i = 1; i<=n && flag; i++) { //求和取余保存 b[i] = s[i] %n; c[b[i]] ++ ; //cout << b[i]<< endl; if (c[b[i]] > 1) { break; flag = 0; ; } } //cout << i<< endl; int j; for (j = 1; j<=n; j++) { if (b[j] == b[i]) break; } //cout << j<< endl; cout << i-j<< endl; for (int k = j+1; k<=i; k++) cout << a[k] << endl; return 0 ; }