首页 > 代码库 > POJ 2356 Find a multiple (dp + 鸽笼原理)
POJ 2356 Find a multiple (dp + 鸽笼原理)
OJ题目:click here~~
题目分析:n个数,从中取若干个数,和为n的倍数。给出一种取法。
因为只要给出其中一种方案就行,鸽笼原理可以求出取出的数为连续的方案。
关于鸽笼原理,点这里~
直接贴过来:
有n+1件或n+1件以上的物品要放到n个抽屉中,那么至少有一个抽屉里有两个或两个以上物品。
如果你知道这个结论:
a1,a2,a3...am是正整数序列,至少存在整数k和r,1<=k<r<=m,使得ak+a(k+1)+...+a(r)是m的倍数。
证明比较简单:
Sk表示前k个数之和,
(1)若Sk%m==0,前k个数就是m的倍数
(2)如果Sn与St模m同余,那么从t+1到n这些数之和模m等于0.
即使你不知道这个结论,DP厉害的话,应该能想到用 前n项的和 去思考的思想
有这个结论知必有解。
贴代码之前,在总结一下鸽笼原理的结论:
推论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
AC_CODE
const int Max_N = 10002; int main(){ int n , a , i , j , yes = 0 , x[Max_N] ,sum = 0 , visit[Max_N]; memset(visit , -1 , sizeof(visit)); while(cin >> n){ for(i = 1;i <= n;i++) scanf("%d",&x[i]); for(i = 1;i <= n;i++){ sum += x[i]; sum %= n; if(sum == 0){ printf("%d\n",i); for(j = 1;j <= i;j++) printf("%d\n",x[j]); yes = 1; break; } else if(visit[sum] != -1){ printf("%d\n",i - visit[sum]); for(j = visit[sum]+1;j <= i;j++) printf("%d\n",x[j]); yes = 1; break; } else visit[sum] = i; } if(!yes) printf("0\n"); } return 0 ; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。