hdu6627 equation(讨论)

本文介绍了一种解决形如∑i=1n∣ai∗x+bi∣=c的绝对值方程组的方法,通过将n个一次函数按零点排序并遍历,判断解的合法性与解的数量,最后对所有解进行排序去重。

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

题目链接

题意:给你一个一个式子 ∑ i = 1 n ∣ a i ∗ x + b i ∣ = c \sum_{i=1}^n|a_i*x+b_i|=c i=1naix+bi=c,让你求出x的所有解,从小到大排序。
思路:因为给的n个一次函数的零点是唯一的,我们对n个函数按照零点从大到小排序,然后遍历n个点,显然当遍历到k时,[1,k]都会取得相反数,然后我们判断当前解是否合法,再判断是否是无穷多解。
讨论完成之后就是对所有解排序,去个重就行了

#include<bits/stdc++.h>

#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back

using namespace std;

LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 1e5 +11;
int t,n,a[N],b[N];
struct uzi
{
    LL a,b;
    int i;
    bool operator <(const uzi &t)const{
        return a*t.b>b*t.a;
    }
}p[N],ans[N];
int cnt,c;
LL L[N],R[N];
int cmp(uzi x,uzi y){
    return x.a*y.b<x.b*y.a;
}
int main(){
     // freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    for(cin>>t;t;t--){
        cin>>n>>c;cnt=0;
        int sta=0;
        for(int i=1;i<=n;i++)cin>>a[i]>>b[i],p[i].a=-b[i],p[i].b=a[i],p[i].i=i;
        sort(p+1,p+1+n);
        for(int i=1;i<=n;i++)L[i]=L[i-1]+a[p[i].i],R[i]=R[i-1]+b[p[i].i];
        for(int i=0;i<=n;i++){//[0,i]为负
            LL la=L[i],ra=R[i];
            LL lb=L[n]-L[i],rb=R[n]-R[i];
                LL da=c-(rb-ra);
                LL ad=lb-la;
                if(ad<0)da=-da,ad=-ad;
                LL x=gcd(abs(da),abs(ad));
            if(i!=n){
                if(da*a[p[i+1].i]+ad*b[p[i+1].i]<0){
                    continue;
                }                
            }
            if(da*a[p[i].i]+ad*b[p[i].i]>0)continue;
            if(lb-la!=0){
                da/=x;
                ad/=x;
                ans[++cnt]={da,ad};
            }else {sta=1;break;}
        }
        if(sta)cout<<-1<<'\n';
        else{
            if(!cnt){cout<<"0\n";continue;}
            int pp=0;
            sort(ans+1,ans+1+cnt,cmp);
            for(int i=1;i<=cnt;i++){
                if(i>1){
                    if(ans[i].a==ans[i-1].a&&ans[i].b==ans[i-1].b)continue;
                }
                pp++;
            }
            cout<<pp<<' ';
            int cn=1;
            for(int i=1;i<=cnt;i++){
                if(i>1){
                    if(ans[i].a==ans[i-1].a&&ans[i].b==ans[i-1].b){
                        continue;
                    }
                }
                if(ans[i].a==0)cout<<"0/1";
                else cout<<ans[i].a<<'/'<<ans[i].b;
                if(pp==cn)cout<<'\n';
                else cout<<' ';
                cn++;
            }
        }
    }    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值