题目大意:
Description
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
Input
Output
----------------------------------------------------------------------------------------我是华丽的分割线--------------------------------------------------------------------------------
这个题目其实算法并不是很难,实际上是求解方程 x+km == y+kn (mod L) ,求k的值,这是一个大数同余方程。
其中算法用到了扩展欧几里得算法,具体算法可以看《算法导论》31.2节。
不过...虽然算法简单,但是……但是……下面进入正题:
《论 while(a>k){a-=k;}与a%=k;的时间效率》
…………………………
悲伤与痛苦都不能化解我对我自己的失望……看来我自己真的很水……
第一次提交的时候发生了TLE...于是我就在想啊,是哪里超时了呢?
我先后研究了 扩展欧几里得算法的时间效率、GDB的使用规则、function(long long*)和function(long long&)在GCC和G++编译器编译出来的效率(应该说基本没有差别)等等、同时仔细查看了别人成功的代码之后,我仍然找不出来为什么我的程序运行的如此之慢,因为别人的代码和我的没有差别啊...
后来的后来...我终于记起好像还有gprof这个工具,于是用他分析终于找到了结症所在:
while(a>k){
a-=k;
}
对此我真的是无法理解!!!!
如果上天再给我一次机会!!!!
我绝对不会写出这么无聊的代码啊!!!!!
浪费我这么多的时间啊!!!!!!
TMD题目要求的还是大数啊,我怎么敢这么写啊啊!!!!!!!!!
程序不跑个十几秒才怪啊!!!!!!!!
…………
总结经验教训如下:
1.分析程序性能的时候,记得除了有gdb的disas以外,还有gprof这个东西(gcc编译的时候加-pg选项)。
2.不要盲目的猜测耗时,要用专业工具!
3.不要做脑残!!!!!!!
贴下代码:(错误如此刺眼!!!)
#include <stdio.h>
typedef long long int numThData;
typedef numThData da;
/*
da getGcd(da a,da b){
if (b==0)
return a;
return getGcd(b,a%b);
}*/
da solvExGcd(da a,da b,da *x,da *y) //ax+by=gcd(a,b)
{
da r,t;
if(b==0)
{
(*x)=1;
(*y)=0;
return a;
}
r=solvExGcd(b,a%b,x,y);
t=(*x);
(*x)=(*y);
(*y)=t-(a/b)*(*y);
return r;
}
int main(){
da r,xG,yG;
da x,y,m,n,L;
da a,b,k;
scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&L);
b=x-y; //这里a和b搞反了让我检查了很长时间
a=n-m;
while(a<0) a+=L;
while(b<0) b+=L;
r=solvExGcd(a,L,&xG,&yG);
if (b%r!=0){
printf("Impossible\n");
return 0;
}
a=a/r;
L=L/r;
b=b/r;
k=(xG*b)%L;
while (k<0){
k+=L;
}
/*********************************
r=solvExGcd(a,L,&xG,&yG);
if (b%r!=0){
printf("Impossible\n");
return 0;
}
k=(xG*b)/r;
while (k<0){
k+=(L/r);
}
while (k>(L/r)){ //这段代码是个bug,超时的罪魁祸首!
k-=(L/r); //为什么不直接用mod来做。。导致消耗了很多时间
}
*********************************/
printf("%lld\n",k);
return 0;
}