比赛
题目
N N N个野人,一开始依次住在山洞 C 1 , C 2 , … , C N C_1,C_2,\dots,C_N C1,C2,…,CN中,第 i i i个野人会沿顺时针向前走 P i P_i Pi个洞住下来。每个野人 i i i有一个寿命值 L L L,至少要多少个山洞才能使没有任何两个野人在有生之年处在同一个山洞。
分析
枚举山洞的数量,计算出(山洞的数量为
p
p
p)
C
i
+
P
i
×
x
≡
C
j
+
P
j
×
x
(
m
o
d
p
)
C_i+P_i\times x≡C_j+P_j\times x(modp)
Ci+Pi×x≡Cj+Pj×x(modp)
移项后得到
P
i
×
x
−
P
j
×
x
≡
C
j
−
C
i
(
m
o
d
p
)
P_i\times x-P_j\times x≡C_j-C_i(mod p)
Pi×x−Pj×x≡Cj−Ci(modp)
设
C
j
−
C
i
C_j-C_i
Cj−Ci减去
p
×
y
p\times y
p×y得到
(
P
i
−
P
j
)
×
x
(P_i-P_j)\times x
(Pi−Pj)×x可得
(
P
i
−
P
j
)
×
x
=
C
j
−
C
i
−
p
×
y
(P_i-P_j)\times x=C_j-C_i-p\times y
(Pi−Pj)×x=Cj−Ci−p×y
移项后
(
P
i
−
P
j
)
×
x
+
p
×
y
=
C
j
−
C
i
(P_i-P_j)\times x+p\times y=C_j-C_i
(Pi−Pj)×x+p×y=Cj−Ci
扩欧找到
x
x
x的答案
所以x的最小整数解是通过
(
P
i
−
P
j
)
×
x
+
p
×
y
=
g
c
d
(
P
i
−
P
j
,
p
)
(P_i-P_j)\times x+p\times y=gcd(P_i-P_j,p)
(Pi−Pj)×x+p×y=gcd(Pi−Pj,p)得到的
最后
x
=
x
∗
(
C
j
−
C
i
)
÷
g
c
d
(
P
i
−
P
j
,
p
)
m
o
d
p
x=x*(C_j-Ci)\div gcd(P_i-P_j,p)mod p
x=x∗(Cj−Ci)÷gcd(Pi−Pj,p)modp
当
x
x
x同时在两个野人的有生之年中,那么继续枚举,否则直接输出山洞的数量。
代码
#include <cstdio>
#include <cctype>
using namespace std;
int n,c[16],p[16],l[16],cave;
int in(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int max(int a,int b){return (a>b)?a:b;}
int exgcd(int a,int b,int &x,int &y){
if (b==0) {x=1;y=0; return a;}
else{
int d=exgcd(b,a%b,y,x);
y-=a/b*x; return d;
}
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) cave=max(cave,c[i]=in()),p[i]=in(),l[i]=in();
while (1){
bool flag=0; int d,x,y,a,b;
for (int i=1;i<n;i++){
for (int j=i+1;j<=n;j++){
a=p[i]-p[j];b=c[j]-c[i];
if (a<0) a=-a,b=-b;
d=exgcd(a,cave,x,y); //扩欧
int cav=cave/d;
x=(x*b/d%cav+cav)%cav;
if (!x) x+=cav;
if (b%d==0&&x<=l[i]&&x<=l[j]) flag=1;//有生之年不会和平
if (flag) break;
}if (flag) break;
}
if (flag) cave++;
else return !printf("%d",cave);
}
}