1004 equation
解方程:
Σ
i
∣
a
i
⋅
x
+
b
i
∣
=
c
\Sigma_i{|a_i\cdot x+b_i|}=c
Σi∣ai⋅x+bi∣=c
我们将每一项
∣
a
i
⋅
x
+
b
i
∣
|a_i\cdot x+b_i|
∣ai⋅x+bi∣的对称轴
x
=
−
a
i
b
i
x=\frac{-a_i}{b_i}
x=bi−ai从小到大排序,在数轴上得到n+1个区间,枚举每个区间。
这样排序使得当前区间左边的项都是 a i ⋅ x + b i a_i\cdot x+b_i ai⋅x+bi,右边的项是 − a j ⋅ x − b j -a_j\cdot x-b_j −aj⋅x−bj。
于是得到方程并化简:
Σ
i
(
a
i
⋅
x
+
b
i
)
−
Σ
j
(
a
j
⋅
x
+
b
j
)
=
c
∴
x
=
c
−
Σ
i
b
i
+
Σ
i
b
j
Σ
i
a
i
−
Σ
j
a
j
\Sigma_i{(a_i\cdot x+b_i)}-\Sigma_j{(a_j\cdot x+b_j)}=c\\ \therefore x=\frac{c-\Sigma_i{b_i}+\Sigma_i{b_j}}{\Sigma_i{a_i}-\Sigma_j{a_j}}
Σi(ai⋅x+bi)−Σj(aj⋅x+bj)=c∴x=Σiai−Σjajc−Σibi+Σibj
然后判这个x是否在当前区间即可。
我比赛时的想法:将每个 − a i b i \frac{-a_i}{b_i} bi−ai带入方程求解,这样就要维护高精度分数。
观察发现只要每一项 ∣ a x + b ∣ |ax+b| ∣ax+b∣的分子分母都是int范围内的,所以只要实现一个高精度分数和int分数的加法即可。
但是没实现。教训是不能乱拉板子。
#include<cmath>
#include<algorithm>
#include<iostream>
#include<stdio.h>
#include<map>
#include<string.h>
#include<queue>
#include<stack>
#include<iomanip>
#include<complex>
#include<set>
#include<assert.h>
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define double long double
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll sa[maxn], sb[maxn];
struct eq {
ll a, b;
}e[maxn];
bool cmp(eq a, eq b) {
return (double)(-a.b) / a.a < (double)(-b.b) / b.a;
}
ll gcd(ll a, ll b) {
return b ? gcd(b, a%b) : a;
}
void print(pair<ll, ll> x) {
if (x.first < 0 && x.second < 0)x.first *= -1, x.second *= -1;
if (x.second<0)x.first *= -1, x.second *= -1;
ll g = gcd(abs(x.first), x.second);
x.first /= g; x.second /= g;
cout << x.first << '/' << x.second;
}
int main() {
ios::sync_with_stdio(0); cin.tie(0);
ll n, b;
int t; cin >> t;
while (t--) {
ll n, c;
cin >> n >> c;
rep(i, 1, n) {
cin >> e[i].a >> e[i].b;
}
sort(e + 1, e + 1 + n, cmp);
rep(i, 1, n) {
sa[i] = sa[i - 1] + e[i].a;
sb[i] = sb[i - 1] + e[i].b;
}
vector<pair<ll, ll> > ans;
bool inf = 0;
rep(i, 0, n) {
if (c - sb[i] + sb[n] - sb[i] == 0 && sa[i] - (sa[n] - sa[i]) == 0) { inf = true; break; }
if (sa[i] - (sa[n] - sa[i]) == 0) { continue; }
pair<ll, ll> x = { c - sb[i] + sb[n] - sb[i], sa[i] - (sa[n] - sa[i]) };
if (i > 0 && (double)x.first / x.second < (double)-e[i].b / e[i].a) continue;
if (i < n && (double)x.first / x.second >= (double)-e[i + 1].b / e[i + 1].a) continue;
ans.push_back(x);
}
if (inf) { cout << -1 << endl; continue; }
if (ans.size() == 0)cout << 0 << endl;
else {
cout << ans.size() << ' ';
for (int i = 0; i < ans.size();i++) {
print(ans[i]); cout << (i==ans.size()-1?'\n':' ');
}
}
}
cin >> t;
return 0;
}