P2520 [HAOI2011]向量 题解
转换题意
为了表述方便,我们设目标向量为 \((s_1,s_2)\),和题目描述稍有差别。
我们首先只考虑目标向量的横坐标。由于横坐标为 \(a\),\(-a\),\(b\),\(-b\) 的向量均可任意使用,我们可以得到一个不定方程 \(xa+yb=s_1\)。
之后,我们再考虑目标向量的纵坐标,由于 \(x+k-k=x\),我们可以得到第二个不定方程 \((x+2k_1)b+(y+2k_2)a=s_2\) 。
联立上述两个不定方程,题意便转化为了这两个不定方程是否有解。
数学推理
单独考虑第一个不定方程,根据扩欧相关知识,我们可以知道该不定方程有解当且仅当 \(\gcd(a,b)\ |\ s_1\),直接判断即可。
然后,我们设第一个不定方程的特解为 \(x_0\),\(y_0\),那么其通解为 \(x_0+k \frac{b}{\gcd(a,b)}\),\(y_0-k\frac{a}{\gcd(a,b)}\)。
把通解带入第二个不定方程,得 \((x_0+k \frac{b}{\gcd(a,b)}+2k_1)b+(y_0-k\frac{a}{\gcd(a,b)}+2k_2)a=s_2\)
移项和整理,得 \(2k_1b+2k_2a=s_2-x_0b-y_0a+k(\frac{a^2-b^2}{\gcd(a,b)})\)
把\(k\)视作已知,故原不定方程有解当且仅当 \(\gcd(2a,2b)\ |\ [s_2-x_0b-y_0a+k(\frac{a^2-b^2}{\gcd(a,b)})]\)
即 \(s_2-x_0b-y_0a+k(\frac{a^2-b^2}{\gcd(a,b)})=-t\gcd(2a,2b)\)
再移项,得 \(t\gcd(2a,2b)+k(\frac{a^2-b^2}{\gcd(a,b)})=s_2-x_0b-y_0a\)
这又是一个不定方程,其有解当且仅当\(\gcd(\gcd(2a,2b),k(\frac{a^2-b^2}{\gcd(a,b)}))\ |\ s_2-x_0b-y_0a\)
该不定方程有解时,原不定方程也一定有解。
结论
当且仅当 \(\gcd(a,b)\ |\ s_1\) 且 \(\gcd(\gcd(2a,2b),k(\frac{a^2-b^2}{\gcd(a,b)}))\ |\ s_2-x_0b-y_0a\) 时,目标向量可以被表示。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
inline int r()
{
int s=0,k=1;char c=getchar();
while(!isdigit(c))
{
if(c=='-')k=-1;
c=getchar();
}
while(isdigit(c))
{
s=s*10+c-'0';
c=getchar();
}
return s*k;
}
int q,x,y,s1,s2;
int exgcd(int a,int b)
{
if(!b)
{
x=1;y=0;
return a;
}
int g=exgcd(b,a%b);
int tmp=x;
x=y;
y=tmp-y*(a/b);
return g;
}
signed main()
{
int a,b;
q=r();
for(int i=1;i<=q;i++)
{
a=r();b=r();s1=r();s2=r();
int g=exgcd(a,b);
if(s1%g)
{
cout<<"N"<<endl;
continue;
}
s1/=g;
int x0=x*s1,y0=y*s1;
int g1=exgcd(2*a,2*b);
x0=(x0%g1+g1)%g1;
y0=(y0%g1+g1)%g1;
int c=s2-x0*b-y0*a;
c=(c%g1+g1)%g1;
int gg=exgcd((a*a-b*b)/g,g1);
if(c%gg)
{
cout<<"N"<<endl;
continue;
}
cout<<"Y"<<endl;
}
}
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15026839.html