the equation
题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10789
先解释题意:首先给你三个数 a b c 有ax+by+c=0,然后给你x和y的范围x1,x2,y1,y2,求在这个范围内有多少对(x,y)是满足条件的。。。
思路: 如果抛开时间复杂度的话,这道是很简单的题,可以说是线性同余的模板题了,直接求出初始的x,然后先通过加减b/(a,b)使x成为>=x1的最小一个,然后再加b/(a,b)趋近x2,在这个过程再判断对应的y是否满足条件。这是很容易想到的方法,而且看起来时间复杂度也只有O(n),但事实就是:这样是会超时的。。也就是说上面的那段话都是无用的...0.0...
当然,另找思路这道题也不难嘛,由于所有x、y都是由一个数加减得来,而且刚开始那对满足条件,加减同样次数得到的还是一对,对,他们还是匹配的,他们存在递推公式: x=xt+k*b/(a,b); y=yt-k*a/(a,b); 也就是说,只要k是一样的,那么满足两个方程的x,y就是一对...
首先还是确定一个大于等于x1的最小x,用k1记住现在的他是由初始值加上多少倍的b/(a,b)得来,然后再找范围内最大的x,同样,标记k2,对y也用k3、k4来标记最小和最大y,然后就比如k1,k2->(1,10),k3,k4->(4,16),那么从第四对到第10对满足条件(x,y都在范围内。。。),所以答案就等于 k2-k3+1;
思路讲完了,可以写代码了,悄悄告诉你们,我在 acm.hust.edu.cn 错了快70次,是看着那个[Wrong answer on test x]从1个慢慢涨到AC的...写了一整天,智商果然不给力啊..0.0...得出一个经验:第十三个样例多半是a=0、b=0的情况,如果卡在第十三个样例,就试试改改这个。。同时他后台数据还不是很给力,估计没有a==0&&b!=0 、a!=0&&b==0,这两种情况的样例,即使你们在这两个条件中把次数填为10086也不会错的。。。
1 #include<stdio.h> 2 typedef long long LL; 3 void exGcd(LL a,LL b,LL &d,LL &x,LL &y) 4 { 5 if(b==0) 6 { 7 d=a; 8 x=1; 9 y=0; 10 return ; 11 } 12 exGcd(b,a%b,d,x,y); 13 LL t=x; 14 x=y; 15 y=t-a/b*y; 16 } 17 LL max(LL a,LL b) 18 { 19 return a>b?a:b; 20 } 21 LL min(LL a,LL b) 22 { 23 return a<b?a:b; 24 } 25 int main() 26 { 27 LL a,b,c,x1,x2,y1,y2,tmp,d,x,y; 28 while(scanf("%I64d%I64d%I64d",&a,&b,&c)!=EOF) 29 { 30 scanf("%I64d%I64d",&x1,&x2); 31 scanf("%I64d%I64d",&y1,&y2); 32 c=-c; //把c移到方程右边 33 LL k1,k2,k3,k4,co=0; 34 if(a==0&&b==0) 35 { 36 if(c==0) 37 co=(y2-y1+1)*(x2-x1+1); 38 } 39 else if(a==0) 40 { 41 if(c%b==0) 42 { 43 tmp=c/b; 44 if(tmp>=y1&&tmp<=y2) co=(x2-x1)+1; 45 } 46 } 47 else if(b==0) 48 { 49 if(c%a==0) 50 { 51 tmp=c/a; 52 if(x1<=tmp&&tmp<=x2) co=(y2-y1)+1; 53 } 54 } 55 else 56 { 57 exGcd(a,b,d,x,y); 58 if(c%d==0) // 不能整除代表无解 59 { 60 x=x*(c/d); 61 y=y*(c/d); 62 LL xt=x,yt=y; 63 LL mx=b/d,my=a/d; 64 mx=mx>0?mx:-mx; //避免麻烦,就全部弄成正的 65 my=my>0?my:-my; 66 if(x>=x1) 67 { 68 x=x-(x-x1)/mx*mx; //如果x大于x1,就不断减少,直到最接近或等于x1 69 } 70 else 71 { 72 x=x+(x1-x)/mx*mx; //接近x1 73 if(x<x1) x+=mx; //如果x还小于x1,就再加一次 74 } 75 k1=(x-xt)/(b/d); //记录k,我们暂且完全抛弃什么正负,反正照着公式算绝对不会错 76 if(x>=x2) //同上 77 { 78 x=x-(x-x2)/mx*mx; 79 if(x>x2) x-=mx; 80 } 81 else 82 { 83 x=x+(x2-x)/mx*mx; 84 } 85 k2=(x-xt)/(b/d); 86 if(y>=y1) 87 { 88 y=y-(y-y1)/my*my; 89 } 90 else 91 { 92 y=y+(y1-y)/my*my; 93 if(y<y1) y+=my; 94 } 95 k4=(y-yt)/(-a/d); 96 if(y>=y2) 97 { 98 y=y-(y-y2)/my*my; 99 if(y>y2) y-=my; 100 } 101 else 102 { 103 y=y+(y2-y)/my*my; 104 } 105 k3=(y-yt)/(-a/d); 106 //到此,k1,k2,k3,k4全部求出来,然后要注意某些情况可能使得k2<k1,负的哦。。 107 co=min(k4,k2)-max(k3,k1)+1; 108 //if(co<0) co=0; 109 if(co<0) co=-co+2; //把它变为正的,同时加上多减的1 110 //printf("mx = %I64d my = %I64d ",mx,my); 帮助找错的。。 111 //printf("xt = %I64d k1 = %I64d k2 = %I64d yt = %I64d k3 = %I64d k4 = %I64d ",xt,k1,k2,yt,k3,k4); 112 } 113 } 114 printf("%I64d ",co); 115 } 116 return 0; 117 }
上面说出现k2<k1的情况看这个。。。
同时,本渣由于无心细细研究,这思路这代码只保证AC,不保证无错,也有可能是后台数据太lou,等以后再细研吧...