做法很简单,写起来容易混。
首先想到去绝对值。因为满足a>0,显然当x增大时ax+b的值也在增大,所以可以对所有(a,b)按从大到小排序。
显然存在n+1个区间,每个区间都可以将式子分为两部分,前半部分均为-ax-b,后半部分均为ax+b。
区间依次为
预处理a和b的负的前缀和与正的后缀和,再枚举每个区间,即可得到当前的表达式。
形如suma*x+sumb=C,若suma为0且sumb为C,则说明无穷解;若suma为0且sumb不为C或者求出的值不在该区间内,则该区间无解;否则可将之以最简分数的形式存入set。
为了便于处理分数,最好统一将分母的负号去掉。
注意判断分数大小时,分子分母的乘积可能爆int,需要使用long long。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int t,n,C,suma,sumb,tmp,sum[4][maxn],fz,fm;
bool f;
struct node{
int a,b;
node(int _a=0,int _b=0):a(_a),b(_b){}
bool operator <(const node &p)const{
return b*1ll*p.a<a*1ll*p.b;
}
}Q[maxn];
set<node> ans;
int main(){
// freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--){
ans.clear(),f=0;
scanf("%d %d",&n,&C);
for(int i=1;i<=n;i++) scanf("%d %d",&Q[i].a,&Q[i].b);
sort(Q+1,Q+1+n);
for(int i=1;i<=n;i++) sum[0][i]=sum[0][i-1]-Q[i].a,sum[1][i]=sum[1][i-1]-Q[i].b;
sum[2][n+1]=sum[3][n+1]=0;
for(int i=n;i>=1;i--) sum[2][i]=sum[2][i+1]+Q[i].a,sum[3][i]=sum[3][i+1]+Q[i].b;
for(int i=0;i<=n;i++){
suma=sum[0][i]+sum[2][i+1],sumb=sum[1][i]+sum[3][i+1];
if(suma==0&&sumb==C){
f=1;break;
}
else if(suma!=0){
fm=suma,fz=C-sumb;
if(fm<0) fz=-fz,fm=-fm;
if((i==0||Q[i].a*1ll*fz<=-Q[i].b*1ll*fm)&&(i==n||Q[i+1].a*1ll*fz>=-Q[i+1].b*1ll*fm)){
tmp=__gcd(abs(fz),abs(fm));
ans.insert(node(fm/tmp,fz/tmp));
}
}
}
if(f) puts("-1");
else{
cout<<ans.size();
for(auto it=ans.begin();it!=ans.end();it++) cout<<" "<<(*it).b<<"/"<<(*it).a;
cout<<"\n";
}
}
return 0;
}