链接:HDU6627 equation
题意:
解方程: ∑ i = 1 N ∣ a i ? x + b i ∣ = C \displaystyle\sum_{i=1}^{N}\left|a_i\cdot x+b_i\right|=C i=1∑N?∣ai??x+bi?∣=C
其中
-
1 ≤ N ≤ 1 0 5 1\le N\le 10^5 1≤N≤105
-
1 ≤ a i ≤ 1000 1\le a_i\le 1000 1≤ai?≤1000
-
? 1000 ≤ b i ≤ 1000 ?1000\le b_i\le1000 ?1000≤bi?≤1000
-
1 ≤ C ≤ 1 0 9 1\le C\le 10^9 1≤C≤109
若有无穷多个解,输出" ? 1 -1 ?1";否则输出解的个数,然后从小到大输出解(最简分数形式)
分析:
就是模拟解方程的过程,先 解出 N N N个 a i ? x + b i a_i\cdot x+b_i ai??x+bi?的零点 k i k_i ki?,然后排好序,得到 N + 1 N+1 N+1个区间:
( ? ∞ , k 1 ) , [ k 1 , k 2 ) , [ k 2 , k 3 ) … , [ k n ? 1 , k n ) , [ k n , + ∞ ) (-\infty,k_1),[k_1,k_2),[k_2,k_3)\dots,[k_{n-1},k_n),[k_n,+\infty) (?∞,k1?),[k1?,k2?),[k2?,k3?)…,[kn?1?,kn?),[kn?,+∞)
这样从右往左遍历区间,每次把对应的 a i , b i a_i,b_i ai?,bi?变成负的(先以正的形式全部加上得到 s u m a , s u m b suma,sumb suma,sumb,之后再从里面减去2倍的 a i , b i a_i,b_i ai?,bi?即可),再验证一下解出来的x是不是在这个区间里面就行。
对于无穷多个解的判断, s u m a ? x + s u m b = C suma\cdot x+sumb=C suma?x+sumb=C,当 s u m a = 0 suma=0 suma=0且 C ? s u m b = 0 C-sumb=0 C?sumb=0时,有无穷多的解。注意,仅当 s u m a = 0 suma=0 suma=0的话只是在该区间无解,应当继续判断。
还要注意判断一下 k k k相同的区间。
还有,排序的时候sort的cmp函数里面不要有 “=”,会出问题…
以下代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e5+50;
const LL INF=0x3f3f3f3f;
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
struct frac
{
LL up;LL down;bool friend operator <(const frac &x,const frac &y){
return x.up*y.down<y.up*x.down;}bool friend operator ==(const frac &x,const frac &y){
return x.up*y.down==y.up*x.down;}bool friend operator <=(const frac &x,const frac &y){
return x.up*y.down<=y.up*x.down;}
};
struct node
{
LL a;LL b;frac k;
}r[maxn];
bool cmp(const node &x,const node &y)
{
return x.k<y.k;
}
frac create(LL a,LL b)
{
LL t=gcd(abs(a),abs(b));frac x;x.up=a/t;x.down=b/t;if(x.down<0){
x.up=-x.up;x.down=-x.down;}return x;
};
LL N,C;
frac ans[maxn],x;
int main()
{
int T;scanf("%d",&T);while(T--){
scanf("%lld %lld",&N,&C);LL suma=0,sumb=0,cnt=0;for(int i=1;i<=N;i++){
scanf("%lld %lld",&r[i].a,&r[i].b);suma+=r[i].a;sumb+=r[i].b;r[i].k=create(-r[i].b,r[i].a);}sort(r+1,r+N+1,cmp);bool inf=false;cnt=0;r[0]=node{
0,0,create(-INF,1)};r[N+1]=node{
0,0,create(INF,1)};for(int i=N+1;i>=1;i--){
suma-=2*r[i].a;sumb-=2*r[i].b;if(r[i].k==r[i-1].k) //k值相同的区间continue;if(suma==0&&C-sumb==0) //无穷解{
inf=true;break;}elsex=create(C-sumb,suma);if(r[i-1].k<=x&&x<r[i].k) //验证x∈[k[i-1],k[i])ans[cnt++]=x;}if(inf)printf("-1\n");else{
printf("%d",cnt);for(int i=cnt-1;i>=0;--i) //从小到大输出解printf(" %lld/%lld",ans[i].up,ans[i].down);printf("\n");}}return 0;
}