BZOJ_1407_[Noi2002]Savage_EXGCD

BZOJ_1407_[Noi2002]Savage_EXGCD

Description

Input

第1行为一个整数N(1<=N<=15),即野人的数目。
第2行到第N+1每行为三个整数Ci, Pi, Li表示每个野人所住的初始洞穴编号,每年走过的洞穴数及寿命值。
(1<=Ci,Pi<=100, 0<=Li<=10^6 )

Output

仅包含一个数M,即最少可能的山洞数。输入数据保证有解,且M不大于10^6。

Sample Input

3
1 3 4
2 7 3
3 2 1

Sample Output

6


对于两个野人$x$和$y$,假设山洞数为$n$,那么需要满足$(c_x+p_x*time)%n=(c_y+p_y*time)%n$方程无解或解不合法。

展开后直接$exgcd$求一下答案判断$time$是否小于$min{L_x,L_y}$

从$max{c_i}$开始枚举,每次$n^{2}$判断是否合法。总时间复杂度$O(MN^{2}log)$,能过。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
inline char nc() {
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd() {
    register int x=0;
    register char s=nc();
    while(s<'0'||s>'9') s=nc();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
    return x;
}
int n,C[20],P[20],L[20];
void exgcd(int a,int b,int &x,int &y,int &p) {
    if(!b) {p=a; x=1; y=0; return ;}
    exgcd(b,a%b,y,x,p),y-=a/b*x;
}
int gcd(int x,int y) {
    return y?gcd(y,x%y):x;
}
int Fabs(int x) {return x>0?x:-x;}
bool judge(int k) {
    int i,j;
    for(i=1;i<=n;i++) {
        for(j=i+1;j<=n;j++) {
            int a=P[i]-P[j],b=k,c=C[j]-C[i],x,y,d;
            //d=gcd(a,b);
            exgcd(a,b,x,y,d);
            if(c%d==0) {
                a/=d,b/=d,c/=d;
                //exgcd(a,b,x,y,d);
                b=Fabs(b);
                x=(x*c%b+b)%b;
                if(!x) x=b;
                if(x<=min(L[i],L[j])) return 0;
            }
        }
    }
    return 1;
}
int main() {
    n=rd();
    int i,maxx=0;
    for(i=1;i<=n;i++) {
        C[i]=rd(); P[i]=rd(); L[i]=rd();
        maxx=max(maxx,C[i]);
    }
    for(i=maxx;i;i++) {
        if(judge(i)) {
            printf("%d
",i); return 0;
        }
    }
}
原文地址:https://www.cnblogs.com/suika/p/9021397.html