这道题目有些变向,像poj1091的那个青蛙,给的是环长,求其它的,而这道题目求的是环长,因为环,那肯定有模,解未知数 所以我一开始想到的是 求解模方程,最后列出了方程 c[i]+k*p[i] == c[j]+k*p[j] (mod m),这样的话稍微变形移项,c[i]-c[j]=k*(p[j]-p[i])+y*m,一看就知道符合扩展欧几里德求解方程,所以想到了扩展欧几里德,但是又不知道怎么办,怎么样去写,因为m值 无法确定,后来想了很久,又重新读题,这时候才看到 m<= 1 000 000,真是瞎了我的钛合金狗眼啊,这样不就可以枚举了吗,因为有n个野人,一旦两两相遇 就可以退出循环,所以 这个 15*15*1 000 000的循环可以得到大大的剪枝,还有m肯定大于野人初始位置最大的那个位置,当然还有最后一点 题目给的时间是 10 000,又瞎了我的狗眼啊 ,当然最后时间是500+ms
#include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<memory.h> #include<set> #define ll long long #define LL __int64 #define eps 1e-8 #define inf 0xfffffff using namespace std; //vector<pair<int,int> > G; //typedef pair<int,int> P; //vector<pair<int,int>> ::iterator iter; // //map<ll,int>mp; //map<ll,int>::iterator p; // #define IN freopen("c:\\Users\\linzuojun\\desktop\\input.txt", "r", stdin) #define OUT freopen("c:\\Users\\linzuojun\\desktop\\output.txt", "w", stdout) int c[22],p[22],l[22]; int n; void clear() { memset(c,0,sizeof(c)); memset(p,0,sizeof(p)); memset(l,0,sizeof(l)); } int exgcd(int a,int &x,int b,int &y) { if(b==0) { x=1; y=0; return a; } int r=exgcd(b,x,a%b,y); int tmp=x; x=y; y=tmp-a/b*y; return r; } bool detal(int b) { int a,r,x0,y0; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { a=p[j]-p[i]; r=c[i]-c[j]; int gcd=exgcd(a,x0,b,y0); if(r%gcd!=0) continue; x0*=r/gcd; gcd=abs(gcd); int MOD=b/gcd; x0=(x0%MOD+MOD)%MOD; if(x0<=l[i] && x0<=l[j])//在寿命结束之前相遇 return 0; } } return 1; } int main(void) { int t; cin>>t; while(t--) { cin>>n; int m=0; for(int i=0;i<n;i++) { cin>>c[i]>>p[i]>>l[i]; m=max(m,c[i]);//枚举肯定从野人所在位置序号最大的那个开始 c[i]--;//小技巧,从0开始比较方便 } while(1) { if(detal(m)) break; m++; } cout<<m<<endl; } }
作者:u010682557 发表于2013-11-22 23:28:18 原文链接
阅读:69 评论:0 查看评论