51nod 1103 N的倍数(抽屉定理)

来源:互联网 发布:用友nc mac客户端下载 编辑:程序博客网 时间:2024/05/19 18:37
一个长度为N的数组A,从A中选出若干个数,使得这些数的和是N的倍数。
例如:N = 8,数组A包括:2 5 6 3 18 7 11 19,可以选2 6,因为2 + 6 = 8,是8的倍数。
Input
第1行:1个数N,N为数组的长度,同时也是要求的倍数。(2 <= N <= 50000)第2 - N + 1行:数组A的元素。(0 < A[i] <= 10^9)
Output
如果没有符合条件的组合,输出No Solution。第1行:1个数S表示你所选择的数的数量。第2 - S + 1行:每行1个数,对应你所选择的数。
Input示例
825631871119
Output示例
22

6

思路:以前看过抽屉定理,觉得这个定理废话。但是看到这道题,感觉真的好神!

因为只有n个数,如果这n个数中,有其中一个数%n为0,那么肯定是直接输出

如果所有的数%n都不为0,那么就可能为1~n-1里的任何一个,但是有n个数。

这就说明,至少有一个数字,会存在2次!

这样看起来没用,但是如果我是维护前缀和,那就有用了。

如果一个前缀和的值出现了2次,我们都知道,那么这一段区间里的数字之和%n就会等于0,那就是答案了

//该题是特判题,输出一个结果即可#include<cstdio>#include<iostream>using namespace std;const int mn=50000+10;int n,a[mn],sum[mn];int main(){scanf("%d",&n);int vis[mn]={0};int f=1;//标志是否已经输出答案 for(int i=1;i<=n;i++){scanf("%d",a+i);if(f)if(a[i]%n==0){puts("1");printf("%d\n",a[i]);f=0;}sum[i]=(sum[i-1]+a[i])%n;if(f)if(!vis[sum[i]]&&sum[i])vis[sum[i]]=i;else{printf("%d\n",i-vis[sum[i]]);for(int j=vis[sum[i]]+1;j<=i;j++)printf("%d\n",a[j]);f=0;}}return 0;}


原创粉丝点击