Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1407
Solution:
由于此题里n的范围很小,因此可以直接从小到大枚举m
那么问题转化为一个判定型问题:已知m,求是否会发生冲突
由于$O(m cdot n^2)$的复杂度符合要求,枚举每一对(i,j)是否会发生冲突即可
可将问题转化为求同余式中最小的x
[(step_i-step_j)xequiv pos_j-pos_i(mod m)]
接下来就是数论里的套路了:
$ax equiv b(mod c)$可以转化为求$ax+cy=b$,我们可以用扩展欧几里得求出x,y值,同时顺便求出GCD。
设$k=c/gcd(a,c)$,$d=gcd(a,c)$
那么方程$ax equiv b(mod c)$的一个特解:$x_0=x cdot (b/d)mod c$。
(如果b不是d的倍数则无解)
并且它的d个解分别为:$x_i=(x_0+i*k)mod c (i in 0,1,2,.....d-1)$。
推导:
$$ax+cy=b$$
$$ax_0+cy_0=b$$
$$a(x-x_0) = c(y_0-y)$$
$$a/d(x-x_0) = c/d(y_0-y)$$
由于$$c/dmid (x-x_0)$$
所以$$x = x_0+c/d*n$$
则方程ax≡b(mod c)的最小解为:$(x_0mod k+k)mod k$
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=20; int n,c[MAXN],p[MAXN],l[MAXN]; int exgcd(int a,int b,int &x,int &y) { if(!b){x=1;y=0;return a;} int ret=exgcd(b,a%b,x,y),t=x; x=y;y=t-a/b*y;return ret; } bool check(int m) { for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++) { int A=p[i]-p[j],B=c[j]-c[i],x,y,GCD=exgcd(A,m,x,y); if(B%GCD) continue; x=((x*B/GCD)%(m/GCD)+abs(m/GCD))%(m/GCD); if(x<=min(l[i],l[j])) return false; } return true; } int main() { cin >> n;int mx=0; for(int i=1;i<=n;i++) cin >> c[i] >> p[i] >> l[i],mx=max(mx,c[i]);//找到最小的初始值 for(int i=mx;i<=1e6;i++) if(check(i)) return cout << i,0; return 0; }
Review:
算是又了解一种套路了吧:
求 $ax equiv b(mod c)$ 中最小的x的公式:$(x_0mod k+k)mod k$ (先用exgcd算出$x_0$)