hdu6627 equation

Problem 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:

∑i=1N|ai⋅x+bi|=C, 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≤105

  • 1≤ai≤1000

  • −1000≤bi≤1000

  • 1≤C≤109

  • 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
题意: 解含n个x绝对值的等式方程。
思路: 对于每个绝对值等式找出x的区间,再进行排序枚举区间,统计解的个数,具体的看代码和注释。

#include <bits/stdc++.h>
using namespace std;
const int N= 1e5 + 10;
typedef long long ll;
ll s1[N], s2[N];
struct node {
	ll a, b;
	double s;
}g[N];
bool cmp(node p, node q) {
	return p.s > q.s;
}
struct note {
	ll x, y;
	double s;
}v[N];
bool cmp1(note p1, note q1) {
	return p1.s < q1.s;
}
map<double, int> ma;
int main() {
	int t;
	scanf("%d", &t);
	ll n, c;
	while (t--) {
		int cnt = 0;
		ma.clear();
		scanf("%lld%lld", &n, &c);
		for (ll i = 1; i <= n; i++) {
			scanf("%lld%lld", &g[i].a, &g[i].b);
			g[i].s = (double)(-1.0) * g[i].b / g[i].a; // 记录每个区间的解 
		}
		sort(g + 1, g + n + 1, cmp); // 从大到小排序 
		s1[0] = 0; s2[0] = 0;
		for (ll i = 1; i <= n; i++) { // 记录当前系数前缀和常数前缀和 
			s1[i] = s1[i-1] + g[i].a;
			s2[i] = s2[i-1] + g[i].b;
		}
		int flag = 0;
		for (ll i = 0; i <= n; i++) {
			ll a1 = s1[n] - 2 * s1[i]; // 获取当前区间解的系数前缀和 
			ll a2 = s2[n] - 2 * s2[i]; // 获取当前区间解的常数前缀和
			ll s = c - a2; // 等式常数移到右边获取最终常数 
			if (a1 == 0 && s == 0) { // 含x项的系数和常数都为0,则有无穷个解 
				flag = 1;
				break;
			} else if (a1 == 0) { // 含x系数为0,无解 
				continue;
			} else {
				ll num1 = abs(s);
				ll num2 = abs(a1);
				ll gc = __gcd(num1, num2); // 求分子和分母的最大公约数 
				double ss = (double)s / a1;
				if ((i == n || ss > g[i+1].s) && (i == 0 || ss <= g[i].s)) {
					// 该区间有解,则该解一定要在区间内,边界只需做个判断 
					if (ma[ss] == 0) { // 答案去重 
						ma[ss]++;
						v[cnt].x = s / gc;
						v[cnt].y = a1 / gc;
						v[cnt].s = ss;
						cnt++;
					}
				}
			}
		}
		if (flag == 1) {
			printf("-1\n");
		} else {
			printf("%lld", cnt);
			sort(v, v + cnt, cmp1);
			for (ll i = 0; i < cnt; i++) {
				if (v[i].x * v[i].y > 0) {
					printf(" %lld/%lld", abs(v[i].x), abs(v[i].y));
				} else if (v[i].x * v[i].y == 0) {
					printf(" 0/1");
				} else {
					printf(" -%lld/%lld", abs(v[i].x), abs(v[i].y));
				}
			}
			printf("\n");
		}
	}
 	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值