sgu 106 the equation

     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\tmy = %I64d\n",mx,my);  帮助找错的。。
111         //printf("xt = %I64d\tk1 = %I64d\tk2 = %I64d\nyt = %I64d\tk3 = %I64d\tk4 = %I64d\n",xt,k1,k2,yt,k3,k4);
112       }
113     }
114     printf("%I64d\n",co);
115   }
116   return 0;
117 }

 

  上面说出现k2<k1的情况看这个。。。

  同时,本渣由于无心细细研究,这思路这代码只保证AC,不保证无错,也有可能是后台数据太lou,等以后再细研吧...

 

  

posted @ 2015-08-14 14:55  hchlqlz  阅读(364)  评论(0编辑  收藏  举报