题目大意
n n 个人在个点的环上,每个人初始在点 ci c i ,能活 Li L i 秒,每秒会向后走 pi p i 步,求出最小的 m m 使得任意两个人在有生之年都不会在一个点上相遇。
解题分析
转化一下这题,如果两个人在第 x x 天相遇了,说明什么?
转移
(pi−pj)x≡ci−cj(Mod m) ( p i − p j ) x ≡ c i − c j ( M o d m )
就是线性模方程,如果算出x无解(这辈子都碰不上)或 x>min(Li,Lj) x > m i n ( L i , L j ) ,则 i,j i , j 一定碰不到,这样可以先找出一个m,再用 n2 n 2 个方程来验证,但是这不满足二分,所以……穷举大法好( ans<=106 a n s <= 10 6 )
示例程序
#include<cstdio>
#define LL long long
using namespace std;
int n;
LL a[20],b[20],c[20],s,ans;
inline void readL(LL &x){
x=0; char ch=getchar();
while ('0'>ch||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
}
void exgcd(LL a,LL b,LL &d,LL &x,LL &y){
if (!b) {d=a; x=1; y=0;}
else {exgcd(b,a%b,d,y,x); y-=x*(a/b);}
}
bool _check(LL tem){
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++){
LL C=((a[i]-a[j])%tem+tem)%tem,A=((b[j]-b[i])%tem+tem)%tem,g,x,y;
exgcd(A,tem,g,x,y);
if (C%g) continue;
int m=tem/g,k=(x*C/g%m+m)%m;
if (k<=c[i]&&k<=c[j]) return false;
}
return true;
}
int main()
{
freopen("savage.in","r",stdin);
freopen("savage.out","w",stdout);
scanf("%d",&n); s=0;
for (int i=1;i<=n;i++){
readL(a[i]); readL(b[i]); readL(c[i]); s=(s<a[i])?a[i]:s;
}
for (ans=s;;ans++) if (_check(ans)) {printf("%d",ans); break;}
return 0;
}