[BZOJ 1407] Savage

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)x\equiv 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/d\mid (x-x_0)$$

所以$$x = x_0+c/d*n$$

 

则方程ax≡b(mod c)的最小解为:$(x_0\mod 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_0\mod k+k)\mod k$  (先用exgcd算出$x_0$)

posted @ 2018-05-28 23:05  NewErA  阅读(145)  评论(0编辑  收藏  举报