2019 HDU 多校 6627 equation---思维

本文介绍了解决HDU 6627问题的方法,通过分析n个绝对值函数的图像,利用预处理技巧找到所有可能的分数解。若存在特定条件,则输出无数解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

题意:

给定n,c求x的所有解,输出其分数形式,如果有无数个解输出-1

题解:画出这n个绝对值函数的图像,发现它们的零点把x轴分成了n+1个区域,每个区域上都会有某个函数是原函数(绝对值符号里的那个函数)取负的形式,所以预处理一下ai,bi的负前缀和、正后缀和,可以直接得到每个区域上具体的一次方程,解方程判断解否在该区间内就可以了,如果存在a==0且b==c的情况那就是无数解了。

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5+5;
ll prea[maxn], preb[maxn], sufa[maxn], sufb[maxn];

struct fenshu{
    ll z1, z2;
}ans[maxn];

struct node{
    ll a, b;
    fenshu z;
    node(ll k1 = 0, ll k2 = 0, ll k3 = 0, ll k4 = 0){a = k1, b = k2, z.z1 = k3, z.z2 = k4;}
}d[maxn];

int cmp(fenshu A, fenshu B){
    ll a1 = A.z1*B.z2, a2 = A.z2*B.z1;
    if(a1 < a2) return -1;
    else if(a1 == a2) return 0;
    else return 1;
}

bool cmp2(node A, node B){
    return cmp(A.z, B.z) < 0;
}

int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        int n, c;
        scanf("%d%d", &n, &c);
        for(int i = 1; i <= n; i++){
           scanf("%lld%lld", &d[i].a, &d[i].b);
           if(d[i].a == 0){
                d[i].z.z1 = 0;
                d[i].z.z2 = 1;
           }
           else{
                ll tmp = __gcd(d[i].a, -d[i].b);
                d[i].z.z1 = -d[i].b/tmp;
                d[i].z.z2 = d[i].a/tmp;
                if(d[i].z.z2 < 0){
                    d[i].z.z2 = -d[i].z.z2;
                    d[i].z.z1 = -d[i].z.z1;
                }
           }
        }
        sort(d+1, d+n+1, cmp2);
        prea[0] = preb[0] = 0;
        sufa[n+1] = sufb[n+1] = 0;
        for(int i = 1; i <= n; i++){
            prea[i] = prea[i-1]+d[i].a;
            preb[i] = preb[i-1]+d[i].b;
        }
        for(int i = n; i >= 1; i--){
            sufa[i] = sufa[i+1]-d[i].a;
            sufb[i] = sufb[i+1]-d[i].b;
        }
        bool flag = false;
        ll cnt = 0;
        for(int i = 0; i <= n; i++){
            ll a = prea[i]+sufa[i+1];
            ll b = preb[i]+sufb[i+1];
            if(a == 0){
                if(b == c){
                    flag = true;
                    break;
                }
            }
            else{
                fenshu temp;
                ll tmp = __gcd(c-b, a);
                temp.z1 = (c-b)/tmp;
                temp.z2 = a/tmp;
                if(temp.z2 < 0){
                    temp.z2 = -temp.z2;
                    temp.z1 = -temp.z1;
                }
                if(i == 0){
                    if(cmp(temp, d[i+1].z) <= 0) ans[cnt++] = temp;
                }
                else if(i == n){
                    if(cmp(temp, d[i].z) > 0) ans[cnt++] = temp;
                }
                else{
                    if(cmp(temp, d[i].z) > 0 && cmp(temp, d[i+1].z) <= 0) ans[cnt++] = temp;
                }
            }
        }
        if(flag){
            printf("-1\n");
        }
        else{
            printf("%d", cnt);
            if(cnt != 0) printf(" ");
            for(int i = 0; i < cnt; i++){
                printf("%lld", ans[i].z1);
                printf("/");
                printf("%lld", ans[i].z2);
                if(i != cnt-1) printf(" ");
            }
            printf("\n");
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值