题解:
该题可以将 ∑|ai⋅x+bi|=C (i=1,2,……,N)看成 F(x)= ∑|ai⋅x+bi|(i=1,2,……,N)这样就构造出一个函数F(x);
利用高中分段函数知识,对于每个绝对值都具有对应的分段点,该分段点即为 -bi/ai;
因此N个分段点可将这一整个函数串最多分成N+1段;
我们知道对于每个分段点(必须是从小到大排序后的):左端去掉绝对值符号不加负号,右端去掉绝对值符号加负号。这样我们可以排序,枚举这些分段点,对于每个分段点来去掉绝对值符号 算一次X;并判对算出的X是否符合要求。
关于X的要求:
1.算出的X,是不是在在两个相邻分段点内(第一个分段点的左端点在负无穷,最后一个分段点的右端点在正无穷)。
2.对于数组 a[] 的和 是否为0;若数组 a 的和为0,需要判断数组 b 的值是否为C,是的话说明X取值是谁都行。
对于最后的打印结果:
1.相同数不需要打印,并且从小到大输出,很自然想到set容器。
2.打印结果要求是最简的分数,所以要除以gcd;
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node
{
int a,b;
double zz;
bool operator < (const node x)const
{
return zz<x.zz;
}
}pp[100005];
int gcd(int x,int y)
{
return y>0?gcd(y,x%y):x;
}
signed main()
{
int T;
scanf("%lld",&T);
while(T--)
{
int N,C;
set <struct node> ans;
int suma=0,sumb=0;
scanf("%lld %lld",&N,&C);
for(int i=1;i<=N;i++)
{
scanf("%lld %lld",&pp[i].a,&pp[i].b);
suma-=pp[i].a;
sumb-=pp[i].b;
pp[i].zz=-1.0*pp[i].b/pp[i].a;
}
sort(pp+1,pp+N+1);
bool ff=false;
for(int i=0;i<=N&&!ff;i++)
{
if(i>0)
suma=suma+2*pp[i].a,sumb=sumb+2*pp[i].b;
if(suma==0)
{
if(sumb==C)
{
ff=true;
continue;
}
}
else
{
double x=1.0*(C-sumb)/suma;
if(i==0&&x<=pp[1].zz||i!=N&&i!=0&&x>pp[i].zz&&x<=pp[i+1].zz||i==N&&x>pp[i].zz)
{
struct node uu;
int g=gcd(abs(C-sumb),abs(suma));
uu.a=(C-sumb)/g;
uu.b=suma/g;
uu.zz=uu.a*1.0/uu.b;
if(uu.zz>0)uu.a=abs(uu.a),uu.b=abs(uu.b);
else
{
if(uu.b<0)uu.a*=-1,uu.b*=-1;
}
ans.insert(uu);
}
}
}
if(ff)printf("-1\n");
else
{
if(ans.size()==0)printf("0\n");
else
{
printf("%lld",ans.size());
set <struct node>::iterator iter=ans.begin();
while(iter!=ans.end())
{
printf(" %lld/%lld",(*iter).a,(*iter).b);
iter++;
}
printf("\n");
}
}
}
return 0;
}