题意:
对于 ∑ 1 n ∣ a i x + b i ∣ = C \sum_1^n|a_ix+b_i| = C ∑1n∣aix+bi∣=C, 求 x x x的所有可行解(分数形式表示)。
思路:
分区间讨论。
我们令
∣
a
i
x
+
b
i
∣
=
0
|a_ix+b_i| = 0
∣aix+bi∣=0,那么就可以得到
n
n
n个关于
a
,
b
a,b
a,b 的解
x
i
x_i
xi,(对每个绝对值编号1~i)
按照
x
i
x_i
xi 的大小(为了避免精度误差,采用交差相乘的方法对
x
i
x_i
xi排序)排序。
然后根据高中知识 (绝对值分类讨论)
假设我们从数轴的最左端开始向右移动, 对于 x i x_i xi到 x i + 1 x_{i+1} xi+1这个区间,区间内的所有实数都会使得 1 1 1— i i i的绝对值内的方程恒正, i + 1 i+1 i+1— n n n的绝对值恒负。
因为我们要求的是可行解,那么对于所有绝对值有 ∑ 1 i a i ∗ x + ∑ 1 i b i = C \sum_1^ia_i*x+\sum_1^ib_i = C ∑1iai∗x+∑1ibi=C
因此我们只需要维护
a
i
a_i
ai 和
b
i
b_i
bi 的前缀和,每次向右移动区间不断更新前缀和就可以了。
其他的就是一些细节。比如注意如果解是负数负号要在分子。注意去重。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
ll gcd(ll a,ll b){
return b==0?a:gcd(b,a%b);
}
struct node{
int a,b;
int id;
bool operator<(const node A)const{
return (-b)*A.a < a*(-A.b);
}
}w[maxn];
struct Node{
ll xa,xb;
bool operator<(const Node A)const{
return xa*A.xb < xb*A.xa;
}
}p[maxn];
int seg[maxn];
int a[maxn],b[maxn];
int n; ll C;
/*
4
5 1001256456
1564 123
15641 4238
563 4156
489 847896
6351 546
2 -1002113415/24608 1000399497/24608
*/
int main(){
int T;
scanf("%d",&T);
while(T--){
map<pair<int,int>, int>mp;
mp.clear();
scanf("%d%lld",&n,&C);
ll suma,sumb;
suma = sumb = 0;
for(int i = 1; i <= n; i++){
scanf("%d%d",&w[i].a,&w[i].b);
suma = suma+(-w[i].a);
sumb = sumb+(-w[i].b);
}
w[n+1].a = w[n+1].b = 0;
sort(w+1,w+n+1);
int cnt = 0,inf = 0,tol = 0;
for(int i = 0; i <= n; i++){
suma += 2*w[i].a;
sumb += 2*w[i].b;
if(suma == 0){
if(sumb == C){
puts("-1");
inf = 1;
break;
}
}else{
ll an1 = C-sumb; //fenzi
ll an2 = suma; //fenmu
ll g = gcd(an1,an2);
if(g < 0){
if(an2 > 0){
an1 = an1/(-g);
an2 = an2/(-g);
}else{
an1 = an1/g;
an2 = an2/g;
}
}else{
if(an2 < 0){
an1 = (-an1)/g;
an2 = (-an2)/g;
}else{
an1 = an1/g;
an2 = an2/g;
}
}
if((ll)an1*(w[i].a) < (ll)an2*(-w[i].b)) continue;
if((ll)an1*(w[i+1].a) > (ll)an2*(-w[i+1].b)) continue;
if(!mp[make_pair(an1,an2)]){
p[tol].xa = an1;
p[tol++].xb = an2;
mp[make_pair(an1,an2)] = 1;
}
}
}
sort(p,p+tol);
if(!inf){
printf("%d", tol);
for(int i = 0; i < tol; i++){
int an1 = p[i].xa;
int an2 = p[i].xb;
printf(" %d/%d",an1,an2);
}
puts("");
}
}
}