2019HDU多校第五场1004--Equation(分区间讨论思想)

 

一.题意:

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;
}

 

 

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值