• 2019HDU暑期多校训练-1004equation-方程求解


    Description

    You are given two integers N,C and two integer sequences a and b of length N. The sequences are indexed from 1 to N.

    Please solve the following equation for x:

    where |v| means the absolute value of v.

    Input

    The first line contains an integer T indicating there are T tests. Each test consists of N+1 lines. The first line contains two integers N,C. The i-th line of following N lines consists of two integers ai,bi.

    • 1≤T≤50

    • 1≤N≤10^5

    • 1≤ai≤1000

    • −1000≤bi≤1000

    • 1≤C≤10^9

    • only 5 tests with N larger than 1000

    Output

    For each test, output one line.
    If there are an infinite number of solutions, this line consists only one integer −1.
    Otherwise, this line first comes with an integer m indicating the number of solutions, then you must print m fractions from the smallest to the largest indicating all possible answers. (It can be proved that all solutions can be written as fractions). The fraction should be in the form of "a/b" where a must be an integer, b must be a positive integer, and gcd(abs(a),b)=1. If the answer is 0, you should output "0/1".

    Sample Input

    4
    2 3
    1 2
    1 -1
    3 3
    2 1
    2 2
    2 3
    2 1
    3 5
    4 -1
    3 2
    1 -1
    1 -2
    1 -3

    Sample Output

    -1
    2 -3/2 -1/2
    0
    1 2/1

    核心思想:

    每个式子|ai⋅x+bi|,都存在一个零点,n个式子最多有n个零点,将n个零点升序排列在x轴上,这样就有n+1个区间。对于任何一个区间,ai⋅x+bi的正负是确定的,也就是可以把绝对值符号去掉。
    枚举每个区间,去掉绝对值符号后合并同类项,得到方程的一个解,若此解在被枚举的区间内,则保留此解,否则舍掉此解。如果某个区间在合并同类项后x的系数为0,则分情况讨论:1、等式恒成立,则此区间任意一个实数都是方程的解,输出-1;2、等式不成立,此区间无解。

    代码如下:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+20;
    //h.v表示零点,chu.v表示解 
    struct node{
    	int a,b;
    	double v;
    }h[N],chu[N]; 
    int sa[N],sb[N];
    bool cmp(node p,node q)
    {
    	return p.v<q.v;
    }
    int main()
    {
    	int T;
    	cin>>T;
    	while(T--)
    	{
    		int n,c;
    		//输入 
    		scanf("%d%d",&n,&c);
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d%d",&h[i].a,&h[i].b);
    			//h.v表示零点 
    			h[i].v=-1.0*h[i].b/h[i].a;
    		}
    		//按零点升序排列 
    		sort(h+1,h+n+1,cmp);
    		//求个前缀和,方便合并同类项 
    		for(int i=1;i<=n;i++)
    		{
    			sa[i]=sa[i-1]+h[i].a;
    			sb[i]=sb[i-1]+h[i].b;
    		}
    		//枚举区间 
    		int cnt=0;
    		int flag=0;
    		for(int i=0;i<=n;i++)
    		{
    			//前i个式子为正
    			//i+1到n个式子为负,要取负得绝对值
    			//ssa=sa[i]-(sa[n]-sa[i]) 
    			int ssa=2*sa[i]-sa[n];
    			int ssb=2*sb[i]-sb[n];
    			//x的系数在合并同类项后为0 
    			if(ssa==0)
    			{
    				if(c-ssb==0)
    				{
    					//解个数无穷,输出-1 
    					flag=1;
    					break;
    				}
    			}
    			//x的系数不是0 
    			else
    			{
    				double te=1.0*(c-ssb)/ssa;
    				//判断解是否在区间内 
    				if((i==0||te>=h[i].v)&&(i+1>n||te<h[i+1].v))
    				{
    					//约分 
    					int t=__gcd(c-ssb,ssa);
    					chu[cnt].a=(c-ssb)/t;
    					chu[cnt].b=ssa/t;
    					//按照题目要求,分子的值要为正 
    					if(chu[cnt].b<0)
    					{
    						chu[cnt].b=-chu[cnt].b;
    						chu[cnt].a=-chu[cnt].a;
    					}
    					chu[cnt].v=te;
    					cnt++;
    				}
    			}
    		}
    		//输出 
    		if(flag)
    		{
    			printf("-1
    ");
    			continue;
    		}
    		sort(chu,chu+cnt,cmp);
    		if(cnt==0)
    			printf("0
    ");
    		else
    		{
    			printf("%d ",cnt);
    			for(int i=0;i<cnt-1;i++)
    				printf("%d/%d ",chu[i].a,chu[i].b);
    			printf("%d/%d
    ",chu[cnt-1].a,chu[cnt-1].b);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    SSH出现ls command not found
    SVN打包备份
    【转】Linux安装JDK1.7 prm
    任务
    java多线程
    JAVA开发中151个建议
    Linux Too Many OpenFiles
    【收藏】Linux tail命令
    Linux读取属性配置文件注意事项
    [转]Linux端口查看命令
  • 原文地址:https://www.cnblogs.com/NothingbutFight/p/11307860.html
Copyright © 2020-2023  润新知