还是不会用代码块,我没救了。
ps:其实想出这么不简便的代码也是挺难的,不鼓励下我么,哭唧唧
思路
主要是利用扩展欧几里得求ax+by=gcd(a,b)特解,然后推出ax1+by1=m的特解
之后枚举m利用二元不定方程特解和数学性质判定是否有>=0的解
代码中注释的是我用来检测这个算法的正确性的,放心完全正确。大佬们可以再复检。
对于前提条件的解释
题目中给出条件说数据一定有解,但咱们也要了解为什么
题目就是求
ax+by=m;【x,y,a,b,m为大于0的整数】中令等式不成立的m的最大值
由裴蜀定理得若是(a,b)>1,则m只要为a,b的倍数时就一定有x,y的整数解【x,y不保证都为正数】,而且m要是足够大,一定有xy的正整数解。这样就没有最大的m使得等式不成立【令m恰好不为(a,b)的倍数就可】
所以(a,b)=1是此题目的前提条件,所以a,b互质。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
//#include<algorithm>
#define MAX 600
long long int x01, y01;
int gcd(int a, int b)
{
if (!b)
{
x01 = 1;
y01 = 0;
return a;
}
else
{
gcd(b, a % b);
int temp = x01;
x01 = y01;
y01 = temp - (a / b) * y01;
}
}
int main(void)
{
int n;
int x, y, a, b;
scanf("%d%d", &a, &b);//输入的包装糖果数就是ax+by=m中的ab
int i = 0;
//现求最大公因数
if (a < b)
{
a += b;
b = a - b;
a -= b;
}
int g = gcd(a, b);
int ans = 0;
for (i = 1; i <= 9000000; i++)//枚举m的值
{
long long int x02 = x01 * i;
long long int y02 = y01 * i;
long long int x_t, y_t;
//特解为x=x0+bt与y=y0-at,x递增,y递减,若是x0为负,令x刚好到达0或是恰好大于0时,y仍为负说明无>=0的整数解
//若x0刚好为正,令y恰好为0或是恰好大于0时,若x为负则无>=0的整数解。
if (x02 <= 0)
{
double t = -1.0 * x02 / b;
if (t > (int)t)
t = (int)t + 1;
y_t = y02 - a * t;
if (y_t < 0)//不可能有xy同时为0的情况
ans = i;
}
else
{
double t = 1.0 * y02 / a;
if (t != (int)t)
t = (int)(t - 1);
x_t = x02 + b * t;
if (x_t < 0)
{
ans = i;
}
}
}
printf("%d\n", ans);
/*if (ans != a * b - a - b&&a*b-a-b<=1000)
printf("错\n%d",a*b-a-b);*/
return 0;
}
另附dp算法作此题目的修改
#include <iostream>
#include <algorithm>
using namespace std;
int n, m, minn, maxx, ans;
bool dp[1000000];
int main() {
cin >> n >> m;
dp[0] = true;
minn = min(n, m);
maxx = max(n, m);
if(minn>1)
ans=1;
for (int i = minn; i < n * m; i++) {
if (dp[i - minn]) {
dp[i] = true;
} else if (i >= maxx && dp[i - maxx]) {
dp[i] = true;
} else {
ans = i;
}
}
cout << ans;
return 0;
}
作者:LAKawai
链接:https://www.acwing.com/solution/content/8421/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
%%% exgcd为什么要写成gcd $awa$
顺手打的手动狗头
其实有O(1)的公式:n*m-n-m
这个公式怎么推导出来?
https://www.acwing.com/solution/content/3165/