[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");
}

 

posted @ 2018-01-07 11:50  TRTTG  阅读(405)  评论(0编辑  收藏  举报