Codeforces - 1244C - The Football Season(暴力 + 数学规律 + 数论 / *2000)
1244C - The Football Season(⇔源地址)
tag
⇔暴力、⇔数学规律、⇔数论、⇔*2000
题意
已知方程 \(\left\{\begin{matrix} x*w+y*d=p \\ x+y+z=n\end{matrix}\right.\) ,且满足 \(d<w\) ,求解一组正整数解 \(\{x,y,z\}\) 。
思路
暴力解(枚举)
第一个突破口很好看出来:由于一式与 \(z\) 无关,故 \(z\) 可以暂时不参与计算;只需要解出一组最小的 \(\{x,y\}\) ,再通过二式计算是否存在 \(z\) 即可。
第二个突破口在于变形一式,有:
我们发现,如果对于一组解 \(\{x_0,y_0\}\) 满足二式,那么一定有一组解 \(\{x_0-d,y_0-w\}\) 也满足二式,而后者的和小于前者,即后者更优。
由此,我们发现,\(y\) 的取值是 \(0\le y < w\) ,暴力枚举 \(y\) 即得解。
一式的变形还有另外一种思路,如下:设 \(y \ge w\) ,那么记 \(y=\Delta + w\)
\[x*w+(\Delta+w)*d=p \]\[\rightarrow (x+d)*w+\Delta * d=p \]
不过,需要注意的是,由此计算出来的值不一定是满足“正整数”这一条件的,如下例:
10 2 5 3
别忘记加上特判(否则会WA62)。
数论解(扩展欧几里得)
本题还能使用数论解,但是会爆 long long
,需要搭配 int128
食用,简单学习了下,过程如下。
由扩欧可得 \(x*w+y*d=\gcd(w,d)\) 的其中一组可行解,记为 \(\{x_0,y_0\}\) ;而当 \(p \mod \gcd(w,d)=0\) 时,可行解变为 \(\bigg\{x_0*\dfrac{p}{\gcd(w,d)},y_0*\dfrac{p}{\gcd(w,d)} \bigg\}\) 。
那么,该如何求解最小的一组 \(\{x,y\}\) 呢,我们还是回到上一种解法的变形上,即:用 \(d\) 个 \(x\) 换 \(w\) 个 \(y\) 。更多思路与代码参考这里 。
AC代码
点击查看代码
bool Solve() {
int n, p, w, d; cin >> n >> p >> w >> d;
int y = 0;
for (int y = 0; y < w; ++ y) {
if ((p - y * d) % w) continue;
int x = (p - y * d) / w, z = n - x - y;
if (x >= 0 && z >= 0) {
cout << x << " " << y << " " << z;
return 0;
}
}
cout << -1;
return 0;
}
错误次数:2
忘写特判了……
文 / WIDA
2023.02.23 成文
首发于WIDA个人博客,仅供学习讨论