[HDU 6627] equation

题目描述:

给出N个Ai和N个Bi 求 解 X 的个数和分数表示,如果无穷个解请输出-1
在这里插入图片描述

题目分析:

高中解方程题目啊
首先 对于每个式子 我们可以找到一个特殊点 G 如果X<G 那么 |aix+bi|= -aix-bi
我们首先把每个式子的G解出来 也就是 (-bi/ai) 然后把这N个式子按照G的大小排序
这样就相当于把一个数轴划分成了N+1个区间,在每个区间里,都有一个不带绝对值的解析式
当我们通过O1的转移得出解析式来时,就可以O1的求出解X了,当然还要判断一下X是否在这个区间内。
对于无穷解的情况,就是存在这样的一个区间 系数Ai的和为0,而Bi的和为Ci,这时方程的值与X无关,区间内的所有值都是这个方程的解,也就是无限个解了。
时间复杂度O(N)
实名感谢出题人不卡Double…

题目链接:

HDU 6627

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
const double inf=0x7fffffff;
const int maxm=1e5+100;
int n,c,cnt;
struct s{
    int x1,x2;
    double ps;
}ans[maxm];
struct node{
    int a,b;
    int x1,x2;
    double js;
}e[maxm];
inline bool comp(node x,node y){return x.js<y.js;}
inline bool com2(s x,s y){return x.ps<y.ps;}
inline bool ok(s x)
{
    for(int i=1;i<=cnt;i++) if((ans[i].x1==x.x1)&&(ans[i].x2==x.x2)) return 0;
    return 1;
}
inline int abs(int x)
{
    if(x<0) x=-x;
    return x;
}
inline void work()
{
    scanf("%lld%lld",&n,&c);
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&e[i].a,&e[i].b);
        e[i].js=(1.0*(-e[i].b))/(1.0*e[i].a);
    } 
    std::sort(e+1,e+n+1,comp);
    int nowa=0,nowb=0;
    for(int i=1;i<=n;i++) nowa+=(-e[i].a),nowb+=(-e[i].b);
    int now=0;
    int flag=0;
    while(1)
    {
        double l,r;
        now==0?l=-inf:l=e[now].js;
        now==n?r=inf:r=e[now+1].js;
        s x=s{c-nowb,nowa,0.0};
        double s=(1.0*c-1.0*nowb)/(1.0*nowa);
        if((s>=l)&&(s<=r))
        {
            int g=std::__gcd(x.x1,x.x2);
            x.x1/=g,x.x2/=g;
            x.ps=s;
            if(ok(x)) ans[++cnt]=x;
        }
        now++;
        if(now==(n+1)) break;
        nowa+=2*e[now].a,nowb+=2*e[now].b;
        if((nowa==0)&&(nowb==c)) flag=1;
        if(flag) break;
    }
    if(!flag)
    {
       printf("%lld",cnt);
       if(cnt) printf(" ");
       if(cnt) std::sort(ans+1,ans+cnt+1,com2);
       for(int i=1;i<=cnt;i++)
       {
        if(ans[i].ps<0) printf("-");
        if(!ans[i].x1) printf("0/1");
        else printf("%lld/%lld",abs(ans[i].x1),abs(ans[i].x2));
        if(i!=cnt) printf(" ");
       }    
    }
    else printf("-1");
    puts("");
}
signed main()
{
    int t;
    scanf("%lld",&t);
    for(int i=1;i<=t;i++) work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值