[USACO4.1]麦香牛块Beef McNuggets
https://www.luogu.org/problemnew/show/P2737
给出n个数ai,求这n个数不能累加出的最大的数
最大的数无限大或能凑出所有的自然数则输出0
n<=10,ai<=256
结论一:
给出两个数a,b
若a,b 能凑出大于某个数的所有自然数
那么由a的倍数组成的数必定能构成模b的完全剩余系
否则 由a的倍数组成的数 不能构成模b的完全剩余系
证明:
若由a的倍数组成的数能构成模b的完全剩余系
那么存在 k1,k2,…… kb 满足 ki*a%b 互不相同
即 ax-by=p
对于 任意的p∈[0,b-1] 一定有x,y 的非负整数解
而由扩展欧几里得定理得
若gcd(a,b)= d
则 ax+by=k*d 一定有整数解,
且一定存在一组解,满足x∈[0,b/d-1],y∈[-a/d+1,0]
所以
若a,b互质,即gcd(a,b)= 1 ,p 必定是1的倍数,所以 由x个a,-y个b,可以凑出%b=p,p∈[0,b-1]的任意数
若a,b不互质,则gcd(a,b)= d,那么只能凑出满足p%d=0 的数
结论二:
若gcd(a,b)=1 ,那么由a,b 不能凑出的最大的数为 a*b-a-b
证明:
1、 由结论一得,a,b 一定存在不能凑出的最大的数
2、证明这个最大的数为 a*b-a-b,即noip2017 day1 t1
参见http://www.cnblogs.com/TheRoadToTheGold/p/8214630.html
所以本题解法:
先判断给出的n个数gcd是否等于1,不等于1则不等凑出的数无穷大,输出0
然后dp[i] 表示数i能否被凑出来,做一遍完全背包即可
从里面找出不能凑出的最大的数
#include<cstdio> using namespace std; #define N 256*256 bool dp[N+1]; int a[11]; int getgcd(int a,int b) { return !b ? a : getgcd(b,a%b); } int main() { int n; scanf("%d",&n); int gcd=0; for(int i=1;i<=n;++i) { scanf("%d",&a[i]); gcd=getgcd(a[i],gcd); } if(gcd!=1) { printf("0"); return 0; } dp[0]=true; for(int i=1;i<=n;++i) for(int j=a[i];j<N;++j) dp[j]|=dp[j-a[i]]; for(int i=N-1;i>=0;--i) if(!dp[i]) { printf("%d",i); return 0; } printf("0"); }