您的位置:首页 > 其它

sgu 106 the equation

2015-08-14 14:55 363 查看
     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也不会错的。。。

  

#include<stdio.h>
typedef long long LL;
void exGcd(LL a,LL b,LL &d,LL &x,LL &y)
{
if(b==0)
{
d=a;
x=1;
y=0;
return ;
}
exGcd(b,a%b,d,x,y);
LL t=x;
x=y;
y=t-a/b*y;
}
LL max(LL a,LL b)
{
return a>b?a:b;
}
LL min(LL a,LL b)
{
return a<b?a:b;
}
int main()
{
LL a,b,c,x1,x2,y1,y2,tmp,d,x,y;
while(scanf("%I64d%I64d%I64d",&a,&b,&c)!=EOF)
{
scanf("%I64d%I64d",&x1,&x2);
scanf("%I64d%I64d",&y1,&y2);
c=-c; //把c移到方程右边
LL k1,k2,k3,k4,co=0;
if(a==0&&b==0)
{
if(c==0)
co=(y2-y1+1)*(x2-x1+1);
}
else if(a==0)
{
if(c%b==0)
{
tmp=c/b;
if(tmp>=y1&&tmp<=y2) co=(x2-x1)+1;
}
}
else if(b==0)
{
if(c%a==0)
{
tmp=c/a;
if(x1<=tmp&&tmp<=x2) co=(y2-y1)+1;
}
}
else
{
exGcd(a,b,d,x,y);
if(c%d==0)  // 不能整除代表无解
{
x=x*(c/d);
y=y*(c/d);
LL xt=x,yt=y;
LL mx=b/d,my=a/d;
mx=mx>0?mx:-mx;   //避免麻烦,就全部弄成正的
my=my>0?my:-my;
if(x>=x1)
{
x=x-(x-x1)/mx*mx; //如果x大于x1,就不断减少,直到最接近或等于x1
}
else
{
x=x+(x1-x)/mx*mx; //接近x1
if(x<x1) x+=mx;   //如果x还小于x1,就再加一次
}
k1=(x-xt)/(b/d);    //记录k,我们暂且完全抛弃什么正负,反正照着公式算绝对不会错
if(x>=x2)           //同上
{
x=x-(x-x2)/mx*mx;
if(x>x2) x-=mx;
}
else
{
x=x+(x2-x)/mx*mx;
}
k2=(x-xt)/(b/d);
if(y>=y1)
{
y=y-(y-y1)/my*my;
}
else
{
y=y+(y1-y)/my*my;
if(y<y1) y+=my;
}
k4=(y-yt)/(-a/d);
if(y>=y2)
{
y=y-(y-y2)/my*my;
if(y>y2) y-=my;
}
else
{
y=y+(y2-y)/my*my;
}
k3=(y-yt)/(-a/d);
//到此,k1,k2,k3,k4全部求出来,然后要注意某些情况可能使得k2<k1,负的哦。。
co=min(k4,k2)-max(k3,k1)+1;
//if(co<0) co=0;
if(co<0) co=-co+2;  //把它变为正的,同时加上多减的1
//printf("mx = %I64d\tmy = %I64d\n",mx,my);  帮助找错的。。
//printf("xt = %I64d\tk1 = %I64d\tk2 = %I64d\nyt = %I64d\tk3 = %I64d\tk4 = %I64d\n",xt,k1,k2,yt,k3,k4);
}
}
printf("%I64d\n",co);
}
return 0;
}


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

。。。

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

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: