equation(一元一次方程 绝对值)

原题: http://acm.hdu.edu.cn/showproblem.php?pid=6627

题意:

给出 ∑ ∣ a i x + b i ∣ = C \sum|a_ix+b_i|=C aix+bi=C,求x的解的个数,如果有无限解输出-1

解析:

先将所有的 a i a_i ai转为正数 ∣ − a i x − b i ∣ |-a_ix-b_i| aixbi,那么显然 x > − b i a i x>-\frac{b_i}{a_i} x>aibi的时候开绝对值后不变,否则为 ∣ − a i x − b i ∣ |-a_ix-b_i| aixbi,那么就遍历一下 n + 1 n+1 n+1个范围,求出对应的 A x + B = C Ax+B=C Ax+B=C x x x

  1. x在对应范围内存在一个解
  2. A = 0 , C − B = ̸ 0 A=0,C-B=\not0 A=0,CB≠0时无解
  3. A = 0 , C − B = 0 A=0,C-B=0 A=0,CB=0时无限解

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod=998244353ll;
const int maxn=1e5+5;
#define rep(i,a,b) for(int i=a;i<=b;i++)

const long double eps=1e-12;
int dcmp(double a){
    return fabs(a)<eps?0:(a>0?1:-1);
}

struct node{
    int a,b;
    long double k;
    bool operator<(const node &P)const{
        return k<P.k;
    }
}e[maxn];

struct A{
    int a,b;
    A(int a,int b):a(a),b(b){}
    A(){}
    bool operator<(const A &P)const{
        return 1.0*a/b<1.0*P.a/P.b;
    }
    bool operator==(const A &P)const{
        return a==P.a&&b==P.b;
    }
};

int suma[maxn],sumb[maxn];
#define pill pair<int,int>
int main(){
    int t;scanf("%d",&t);
    while(t--){
        int n;
        int C;
        scanf("%d%d",&n,&C);
        int ct=0;
        rep(i,1,n){
            scanf("%d%d",&e[i].a,&e[i].b);
            if(e[i].a==0){
                C-=abs(e[i].b);
                continue;
            }
            if(e[i].a<0){
                e[i].a*=-1;
                e[i].b*=-1;
            }
            e[i].k=-(long double)e[i].b/(long double)e[i].a;
            e[++ct]=e[i];
        }
        n=ct;
        sort(e+1,e+1+n);
        rep(i,1,n){
            suma[i]=suma[i-1]+e[i].a;
            sumb[i]=sumb[i-1]+e[i].b;
        }
        bool inf=0;
        set<A>S;
        rep(i,0,n){
            int sa=-(suma[n]-suma[i])+suma[i],sb=-(sumb[n]-sumb[i])+sumb[i];
            sb=C-sb;
            if(sa==0&&sb==0){
                inf=1;break;
            }
            if(sa==0){
                continue;
            }
            long double ans=(long double)sb/(long double)sa;
            bool can=0;
            if(i==n&&dcmp(ans-e[n].k)>=0)can=1;
            if(i==0&&dcmp(ans-e[1].k<=0))can=1;
            if(i!=0&&i!=n&&dcmp(ans-e[i+1].k<=0)&&dcmp(ans-e[i].k>=0))can=1;
            if(!can)continue;
            if(sa<0){
                sa*=-1;
                sb*=-1;
            }
            int G=__gcd(abs(sa),abs(sb));
            sa/=G,sb/=G;
            S.insert(A(sb,sa));
        }
        if(inf){
            printf("-1\n");
            continue;
        }
        printf("%d",S.size());
        for(auto it=S.begin();it!=S.end();it++){
            printf(" %d/%d",it->a,it->b);
        }
        putchar('\n');
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值