一.題意:
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;
}