19杭电暑假多校 第五场 1004 equation (分区间讨论)

题目来源
http://acm.hdu.edu.cn/showproblem.php?pid=6627

题意

给你两个数字n和c,然后给你两个序列 ai , n 个 bi,它们元素个数都为n个。
然后要让你求解一个方程
在这里插入图片描述
输出所有x的可能的解。

思路

对于每个 ∣ a i ∗ x + b i ∣ |a_i * x + b_i| aix+bi
x > − b i / a i x>-b_i/a_i x>bi/ai时, ∣ a i ∗ x + b i ∣ = a i ∗ x + b i |a_i * x + b_i| = a_i * x + b_i aix+bi=aix+bi
x &lt; − b i / a i x&lt;-b_i/a_i x<bi/ai时, ∣ a i ∗ x + b i ∣ = − ( a i ∗ x + b i ) |a_i * x + b_i| = -(a_i * x + b_i) aix+bi=(aix+bi)

然后重点在于肯定有个零点,我们根据这n个 a i b i a_i b_i aibi就能获得n个零点,把这个数轴分为n + 1个区间,然后我们一个区间一个区间讨论答案即可。

代码

#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;//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;//x的值
    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 tem;
        tem.a = x / z, tem.b = y / z;//化最简
        if(ans < 0)//如果ans的值小于0,答案加个负
            tem.a *= -1;
        que.push(tem);
    }
}
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;//从最左边开始,所以假设所有的绝对值去掉后都是负的
        }
        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 tem = que.front();
                que.pop();
                printf(" %d/%d", tem.a, tem.b);
            }
            printf("\n");
        }
    }
    return 0;
}

参考来源

博客
https://blog.csdn.net/qq_41117236/article/details/98600217

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值