CodeForces - 492E Vanya and Field(逆元)
题目大意
给出一个 n × n n\times n n×n的坐标纸,其上有m棵苹果树,给出 d x , d y dx,dy dx,dy假设当前位置为 x , y x,y x,y则每次行动之后的位置会变成 ( x + d x ) m o d n , ( y + d y ) m o d n (x+dx)mod\ n,(y+dy)mod\ n (x+dx)mod n,(y+dy)mod n问从哪个位置开始可以经过尽可能多的苹果树
解题思路
对于一个给定的位置
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0)其能经过的所有点都可以表示为
x
0
+
k
∗
d
x
≡
x
(
m
o
d
n
)
y
0
+
k
∗
d
y
≡
y
(
m
o
d
n
)
x_0+k*dx\equiv x(mod\ n)\\ y_0+k*dy\equiv y(mod\ n)
x0+k∗dx≡x(mod n)y0+k∗dy≡y(mod n)
其中
x
,
y
x,y
x,y为从初始位置开始所能经过所有的点的位置的坐标
由于
g
c
d
(
d
x
,
n
)
=
1
,
g
c
d
(
d
y
,
n
)
=
1
gcd(dx,n)=1,gcd(dy,n)=1
gcd(dx,n)=1,gcd(dy,n)=1因此可对上二式除dx,dy(且一定有逆元),则变成
x
0
∗
i
n
v
(
d
x
)
+
k
≡
x
∗
i
n
v
(
d
x
)
(
m
o
d
n
)
y
0
∗
i
n
v
(
d
y
)
+
k
≡
y
∗
i
n
v
(
d
y
)
(
m
o
d
n
)
x_0*inv(dx)+k\equiv x*inv(dx)(mod\ n)\\ y_0*inv(dy)+k\equiv y*inv(dy)(mod\ n)
x0∗inv(dx)+k≡x∗inv(dx)(mod n)y0∗inv(dy)+k≡y∗inv(dy)(mod n)
上下两个式子做差,则有
x
0
∗
i
n
v
(
d
x
)
−
y
0
∗
i
n
v
(
d
y
)
≡
x
∗
i
n
v
(
d
x
)
−
y
∗
i
n
v
(
d
y
)
(
m
o
d
n
)
x_0*inv(dx)-y_0*inv(dy)\equiv x*inv(dx)-y*inv(dy)(mod\ n)
x0∗inv(dx)−y0∗inv(dy)≡x∗inv(dx)−y∗inv(dy)(mod n)
其中
x
0
∗
i
n
v
(
d
x
)
−
y
0
∗
i
n
v
(
d
y
)
x_0*inv(dx)-y_0*inv(dy)
x0∗inv(dx)−y0∗inv(dy)为一常数,由此可得所有
(
x
∗
i
n
v
(
d
x
)
−
y
∗
i
n
v
(
d
y
)
)
m
o
d
n
(x*inv(dx)-y*inv(dy))mod\ n
(x∗inv(dx)−y∗inv(dy))mod n相等的点之间都可以互相到达.因此依之进行统计即可
AC代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> pii;
typedef long long LL;
unordered_map<LL,int> mpn;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(int a,int mod){
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}
int32_t main()
{
int n,m,dx,dy;
cin>>n>>m>>dx>>dy;
int invdx=getInv(dx,n),invdy=getInv(dy,n);
int x,y;
int nums=0;
pii ans;
while(m--)
{
cin>>x>>y;
int xy=((1LL*x*invdx-1LL*y*invdy)%n+n)%n;
if(!mpn.count(xy))
{
mpn[xy]=1;
}
else mpn[xy]++;
if(mpn[xy]>nums) nums=mpn[xy],ans=pii(x,y);
}
cout<<ans.first<<' '<<ans.second<<endl;
}