一.题意:
http://acm.hdu.edu.cn/showproblem.php?pid=6627
给出所有a[i],b[i]和c的情况下求x的所有解,无解输出-1;
二.分析
观察到绝对值函数具有一定单调性及对称性,必有且仅有一个零点,且在零点处正负发生变化。
所以我们可以求出每个零点,划分为n+1个区间,先假设x接近负无穷,即去绝对值为-ax-b,判断x是否在区间内,然后x往右平移,经过一个零点后一组a,b负变为正,重复以上操作,注意特殊值判断即可。
三,代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const ll INF = 1e18;
struct node{
int a, b;
double x;//零点
int id;
}f[maxn];
bool cmp(node a, node b)
{
return a.x == b.x ? a.id < b.id : a.x < b.x;
}
int n, c;
int A, B;//累加值
bool flag;//是否有无穷多解
queue <node> que;//因为已经从小到大取,所以不需要优先队列
void solve(double l, double r)
{
if(A == 0 && B == c){//有无穷多解
flag = true;
return ;
}
double ans = (double)(c - B) / A;
if(ans > l && ans <= r){//如果解在区间里
int x = abs(c - B), y = abs(A);
int z;
if(x == 0) z = y;// 0/1的情况
else z = __gcd(x, y);
node t;
t.a = x / z, t.b = y / z;//化最简分数
if(ans < 0)//因为前面用了abs
t.a *= -1;
que.push(t);
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
while(!que.empty())
que.pop();
scanf("%d %d", &n, &c);
A = 0, B = 0, flag = false;
for(int i = 1; i <= n; ++i)
{
int a, b;
scanf("%d %d", &a, &b);
f[i].a = a, f[i].b = b, f[i].id = i;
f[i].x = -1.0 * f[i].b / f[i].a;//零点
A -= a, B -= b;
//核心,先假设全部为负,即从最左边开始,平移x
}
sort(f + 1, f + 1 + n, cmp);
double l = -INF, r = -INF;
f[n + 1].x = INF;
for(int i = 1; i <= n + 1; ++i)
{
l = r, r = f[i].x;
solve(l, r);
A += 2 * f[i].a, B += 2 * f[i].b;//逐个负的变成正的
}
if(flag)
printf("-1\n");
else
{
printf("%d", que.size());
while(!que.empty())
{
node cnt = que.front();
que.pop();
printf(" %d/%d", cnt.a, cnt.b);
}
printf("\n");
}
}
return 0;
}