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
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\n",i); return 0; } } }