[BZOJ 1407] Savage

Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1407

Solution:

由于此题里n的范围很小,因此可以直接从小到大枚举m(O(m*n^2))

那么问题转变为一个判定性问题:已知m,问所有野人在它们的有生之年里是否会出现冲突

 由于O(m*n^2)的复杂度符合要求,枚举每一对(i,j)是否会发生冲突即可

可将问题转化为求次同余式中最小的x

\[(step_i-step_j)x\equiv pos_j-pos_i(\mod m)\]

接下来就是数论里的套路了:

ax≡b(mod c)可以转化为求ax+cy=b,我们可以用扩展欧几里得求出x,y值,同时顺便求出GCD。

设k=c/GCD(a,c),

那么方程ax≡b(mod c)的一个特解:x0=x*(b/GCD(a,c))%c。(如果b不是GCD(a,c)的倍数则无解)

并且它的GCD(a,c)个解分别为:xi=(x0+i*(k))%c,{i=0,1,2,.....GCD(a,c)-1}。

方程ax≡b(mod c)的最小解为:(x0%k+k)%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;
}
 

猜你喜欢

转载自www.cnblogs.com/newera/p/9102824.html