2019 Multi-University Training Contest 5 1004 equation数学

本文探讨了一种解决含多个绝对值表达式的线性方程组的方法,通过将每个绝对值表达式转换为正负两种情况,利用排序和迭代更新策略,有效地找到了所有可能的解。特别地,代码中使用了C++实现这一算法,包括重载运算符以去除重复解。

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

题意:,给你c和n个ai,bi,让你求出x的所有解

题解:因为每个式子如果小于0即再取绝对值就相当于取个负号,所以每个区间内的式子正负都是决定好的,直接求每个区间内的x即可

思路倒是好理解,代码比较难写,我的代码借鉴了这里 ,具体讲一下代码怎么写的吧,首先按照-bi/ai的大小排序

然后把所有的ka=-∑ai,kb=-∑bi,相当于所有的都是负的情况,然后不停的对ka+=2*ai,kb+=2*bi说明前几个是正的后面全是负的

如果中间出现了ka==0,kb==c的情况说明x有无限个情况,直接-1,取完所有的值之后别忘了去重,我这里重载的==号就可以用unique函数了(代码真的妙啊ORz)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define mem(s) memset(s, 0, sizeof(s))
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const int maxn = 1e6+5;
const int mod = 998244353;
struct node {
    ll a,b;
    bool operator ==(const node &rhs)const{
        if(a==rhs.a&&b==rhs.b)return 1;
        else return 0;
    }
}ans[maxn],a[maxn];
int n,c;
bool cmp(node a,node b){
    return a.b*b.a<b.b*a.a;
}
int main() 
{
    int t;
    scanf("%d",&t);
    while(t--){
        int coun=0,flag=0;
        memset(a,0,sizeof(a));
        ll ka=0,kb=0;
        scanf("%d%d",&n,&c);
        for(int i=1;i<=n;i++){
            scanf("%lld%lld",&a[i].a,&a[i].b);
            ka-=a[i].a,kb-=a[i].b;
            a[i].b*=-1;
        }
        sort(a+1,a+1+n,cmp);
        for(int i=0;i<=n;i++){
            ka+=2*a[i].a;
            kb+=-2*a[i].b;
            if(ka==0&&kb==c){
                flag=1;
                break;
            }
            ll bb=c-kb;
            ll aa=ka;
            if(aa<0){
                aa*=-1;
                bb*=-1;
            }
            ll g=__gcd(aa,abs(bb));
            if(bb*a[i+1].a<=a[i+1].b*aa&&a[i].a*bb>=a[i].b*aa){
                ans[++coun].a=aa/g;
                ans[coun].b=bb/g;
            }
        }
        if(flag){
            printf("-1\n");
            continue;
        }
        sort(ans+1,ans+1+coun,cmp);
        coun=unique(ans+1,ans+1+coun)-(ans+1);
        if(coun==0){
            printf("0\n");
            continue;
        }
        printf("%d ",coun);
        for(int i=1;i<=coun;i++){
            printf("%lld/%lld",ans[i].b,ans[i].a);
            if(i==coun)printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值