Time Limit: 1000MS | Memory Limit: 65536K | |||
Total Submissions: 6595 | Accepted: 2878 | Special Judge |
Description
Input
Output
Sample Input
5 1 2 3 4 1
Sample Output
2 2 3
抽屉原理典型应用:一个由n个数组成的数列 一定能找出若干个连续的数使它们之和能被n整除。
解释:n个数记为a[1],a[2],...a[n].设置一个数组sum,其存储信息为sum[i] = a[1] + a[2] + ...a[i];
情况一:存在一个k(1 <= k <= n),使得sum[k] % n == 0,那么就得证;
情况二:对于任意的k(1 <= k <= n),都有sum[k] % n != 0。 那么 对于n个sum数组的元素将会得到n个余数(即sum[k] % n且这些余数大于0且小于n)。这样对于n个余数(1 <= 余数 <= n-1),我们一定可以找到两个相等的余数,且它们对应sum数组中的start和end元素,使得(sum[end] - sum[start]%n==0。得证。
代码实现: (后面有简单点的思路)
#include <cstdio> #include <cstring> #define MAX 10000+10 using namespace std; int a[MAX], sum[MAX], vis[MAX]; int main() { int n, i, j; int start, end;//start记录连续数列第一个数的位置 end记录最后一个数的位置 int exist;//判断是否已经找到重复余数 int mark;//记录重复的余数 while(scanf("%d", &n) != EOF) { memset(vis, 0, sizeof(vis)); memset(sum, 0, sizeof(sum)); exist = 0; mark = 0; start = end = 0; for(i = 1; i <= n; i++) { scanf("%d", &a[i]); if(exist)//已经找到 continue; sum[i] += a[i] + sum[i-1]; if(sum[i]%n == 0)//直接能被n整除 { exist = 1; start = 1; end = i; continue; } if(vis[sum[i]%n]) //余数已经出现过 { exist = 1; mark = sum[i]%n;//记录重复余数 end = i;//记录结束位置 continue; } else vis[sum[i]%n] = 1; } if(start == 1)//起点从1开始的 { printf("%d\n", end); for(i = 1; i <= end; i++) printf("%d\n", a[i]); } else//起点不是从1开始的 { for(i = 1; i <= n; i++) { if(sum[i]%n == mark)//找到第一个出现重复余数的位置 { start = i+1;//记录位置 break; } } printf("%d\n", end-start+1); for(i = start; i <= end; i++) printf("%d\n", a[i]); } } return 0; }
还有一种更方便的思路:用vis[i]记录余数为i时的数字位置。当检测到a[i]时,余数为k, 若直接整除start = 1,end = i; 若余数k已出现过 start = vis[k]+1,end = i。这样就避免再次查找起点位置的步骤。 还有一点:可以用sum代替sum数组实现。
#include <cstdio> #include <cstring> #define LL long long #define MAX 10000+10 using namespace std; LL sum;//防止超int int a[MAX], vis[MAX]; int main() { int i, j, n; int exist, start, end; while(scanf("%d", &n) != EOF) { sum = 0; exist = 0; memset(vis, 0, sizeof(vis)); for(i = 1; i <= n; ++i) { scanf("%d", &a[i]); if(exist) continue; sum += a[i]; if(sum % n == 0) { exist = 1; start = 1; end = i; continue; } if(!vis[sum%n]) vis[sum%n] = i; else { exist = 1; start = vis[sum%n]+1; end = i; } } printf("%d\n", end-start+1); for(i = start; i <= end; i++) printf("%d\n", a[i]); } return 0; }