2019hdu暑假多校第5场1004 equation HDU - 6627

You are given two integers N,CN,C and two integer sequences aa and bb of length NN. The sequences are indexed from 11 to NN. 

Please solve the following equation for xx: 

i=1N|aix+bi|=C∑i=1N|ai⋅x+bi|=C, where |v||v| means the absolute value of vv.

题意:

给出2个数N,c。然后给出长度为N的2个序列a,b。列出等式|a1*x+b1|+|a2*x+b2|+|a3*x+b3|+......|an*x+bn|=c.

问x的解的个数,如果有无穷个输出-1.否则,输出个数之后,按x/y(x,y均为int型)的格式输出所有答案。

思路: 

对于每一对ai,bi。维护一个double 型的p=1.0*ai/bi。然后可以想到,按p分区间,可以分出N+1个区间。

从最左边往右,分别表示有0个绝对值内为正,有1个绝对值内为正。。。。有i个绝对值内为正。

对于第i个区间,我们可以用O(1)的复杂度求出x的系数和记为A,以及等号左边的常数记为B。

 我们不妨把ai,bi按pi进行排序。那么到底i个区间时,即为aj*x+bj>0(j<=i)。我们一开始令A=-a1-a2-a3......-aN,B=-b1-b2-b3......-bN.那么每一次我们只需A+=2*ai,B+=2*bi.

即为当前区间对应的A,B。那么我们就可以求出一个对应的x。然后判一下所求的x是否在区间内就可以了。

 对于无穷答案的情况就是A==0&&B==c。在A==0的时候特判一下就好了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn = 1e5+5;

struct node
{
    int a,b;
    double p;
} gj[maxn];

struct nodee
{
    int a,b;
} ans[maxn],an[maxn];

bool cmp(node x,node y)
{
    return x.p<y.p;
}

int main()
{
    //freopen("1.in","r",stdin);
    int t,cas=0;
    scanf("%d",&t);
    while(t--)
    {
        int n,c;
        scanf("%d%d",&n,&c);
        for(int i=1; i<=n; i++)
        {
            int a,b;
            scanf("%d%d",&gj[i].a,&gj[i].b);
            gj[i].p=-(gj[i].b*1.0)/gj[i].a;
        }
        sort(gj+1,gj+1+n,cmp);
        int A=0,B=0;
        for(int i=1; i<=n; i++)
        {
            A-=gj[i].a;
            B-=gj[i].b;
        }
        int cnt = 0,ok=0;
        double pre=-1e10;
        gj[0].a=gj[0].b=0;
        gj[n+1].a=gj[n+1].b=0;
        for(int i=0; i<=n;)
        {
            do
            {
                A+=2*gj[i].a;
                B+=2*gj[i].b;
            }
            while(i<=n&&gj[i+1].p==gj[i++].p); //会出现相同的p,所以要把相同的p放在一起算。

            if(A==0&&B!=c)
            {
                pre=-1.0*gj[i].b/gj[i].a;
                continue;
            }
            else if(A==0&&B==c)
            {
                ok=1;    //无穷个解
                break;
            }
            else
            {
                int x=c-B,y=A;
                int X=abs(x),Y=abs(y);
                int z=__gcd(X,Y);
                x/=z;
                y/=z;
                double tmp = x*1.0/y;
                double ttt;
                if(i==n+1)ttt=1e17;
                else ttt=-1.0*gj[i].b/gj[i].a;
                if(pre<=tmp&&tmp<=ttt) //判断答案是否在边界内
                {
                    ans[cnt].a=x;
                    ans[cnt++].b=y;
                }
            }
            pre=-1.0*gj[i].b/gj[i].a;
        }
        if(ok) puts("-1");
        else if(cnt == 0) puts("0");
        else
        {
            int num=0;
            for(int i=0; i<cnt; i++)
            {
                if((ans[i].a>0&&ans[i].b>0)||(ans[i].b<0&&ans[i].a<0)) ans[i].a=abs(ans[i].a),ans[i].b=abs(ans[i].b);
                else if(ans[i].a>0&&ans[i].b<0)
                {
                    ans[i].b=-ans[i].b,ans[i].a=-ans[i].a;
                }
                else if(ans[i].a==0) ans[i].b=1;
                if(i)
                {
                    if(!(ans[i].a==ans[i-1].a&&ans[i].b==ans[i-1].b)) an[num].a=ans[i].a,an[num++].b=ans[i].b;
                }
                else an[num].a=ans[i].a,an[num++].b=ans[i].b;
            }

            printf("%d ",num);
            for(int i=0; i<num; i++)
            {
                printf("%d/%d",an[i].a,an[i].b);
                if(i==num-1)puts("");
                else printf(" ");
            }
        }
    }
    return 0;
}

  

posted @ 2019-08-06 10:11  一只球球  阅读(143)  评论(0编辑  收藏  举报