USACO 4.1.1 麦香牛块 Beef McNuggets

题目大意

给你(n)个数(a_1, a_2 ... a_n), 要你求最大的正整数(m)使得方程(a_1 x_1 + a_2 x_2 + ... + a_n x_n = m)无非负整数解. 题目数据满足(a_x)为正整数且不大于(256), (n le 10).

Solution

先看一个定理: 对于正整数(p), (q)满足(gcd(p, q) = 1), 我们有(px + qy = n)无非负整数解的最大正整数(n)(pq - p - q). 证明如下:
我们首先利用反证法, 证明(px + qy e pq - p - q): 我们假设存在正整数(x)(y)使得(px + qy = pq - p - q), 则有

[px + qy = pq - p - q \ p(x + 1) + q(y + 1) = pq \ ecause gcd(p, q) = 1且p | q(y + 1) \ herefore p | y + 1 \ 同理, q | x + 1 ]

接着我们令(y + 1 = pj), (x + 1 = qk). 则有

[pqk + qpj = pq \ pq(j + k) = pq ]

注意到(x, y ge 0), 我们有(y + 1 ge 1)(x + 1 ge 1), 因而(j ge 1)(k ge 1). 因而(j + k ge 2), 因而假设不成立.
得证.
再证明当(n ge pq - p - q + 1)时原方程总有非负整数解:
我们令(n = pq - p - q + k), 则根据扩展欧几里得定理, 方程(pa + qb = k)有整数解(其中(a)(b)中必有一个为正, 一个为负). 我们假设(a < 0 < b), 调整(a)(b)的值使得(|a| < q). 令此时的(a)(b)分别为(A)(B).
回到原方程

[px + qy = pq - p - q + k \ px + qy = pq - p - q + Ax + By \ p(x + 1 - A) + q(y + 1 - B) = pq ]

根据前面的结论, 我们又有

[p | y + 1 - B \ q | x + 1 - A ]

因此我们令

[j = frac{x + 1 - A} q \ k = frac{y + 1 - B} p ]

则有

[pq(i + j) = pq \ i + j = 1 ]

不妨设(i = 0)(j = 1), 则

[egin{cases} y + 1 - B= 0 \ x + 1 - A = q end{cases} ]

因而

[y = B - 1 \ x = A + q - 1 ]

由于(B > 0), 因而(B - 1 ge 0);
根据之前定义, 我们又有(|A| < q), 因而(A + q - 1 ge 0)
因而原方程必有非负整数解.

好了, 现在考虑这道题怎么做233
注意到(a)值较小, 我们直接从0开始到(256^2)背包暴力即可.
我们注意到(a)之间并不一定互质, 但这并不影响我们枚举的范围.

#include <cstdio>
#include <cctype>

const int N = 10, LIM = 256;
int a[N], f[LIM * LIM << 2];
int main()
{
    int n; scanf("%d", &n);
    for(int i = 0; i < n; ++ i) scanf("%d", a + i);
    f[0] = 1;
    for(int i = 1; i < LIM * LIM << 2; ++ i) for(int j = 0; j < n; ++ j) if(i - a[j] >= 0 && f[i - a[j]])  f[i] = 1;
    int ans = 0;
    for(int i = 1; i < LIM * LIM << 2; ++ i) if(! f[i]) ans = i;
    printf("%d
", ans > LIM * LIM ? 0 : ans);
}

原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7467060.html