問題の意味の説明
あなたは(3 \)\配列を\(a_iを\)、\ (b_i \)と\(C_I \) 、あなたは配列を維持することができます\(X_Iを\)の合計\(m個\)グループは、各尋ねました二つの数字所与\(S \)、\ (T \) 、その結果、
\ [\ sum_i a_iをX_I = S \ qquad \ sum_i b_i X_I = T \]
あなたが探してみよう(\最大{} \ sum_i C_I X_I \ mathrm)\。
練習
見かけ上の問題が持つ線形プログラミングモデルです\(X \)、\ (Y \) 、利用可能を使用したデュアルコンバージョン二つの新しい変数を表し、
\ [\開始{スプリット}&\のmathrm {最小} \ qquad&SX + TY \\&\ mathrm {満足} \ qquad&\ I FORALL、a_ix + b_iy \ GEQ C_I \\&&X、Rのy \ \端{スプリット} \]
メンテナンスは半断面平面を発見することができ、半平面クロス前処理のための\(SX + 1 TY \)複雑性を見つけるために直線、二点/第三の極端な値に変換した\(O((N + Mを)は、n-ログ\)\) 。
コード
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define db double
#define ll long long
#define in inline
#define ak *
in char getch()
{
static char buf[10000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000,stdin),p1==p2)?EOF:*p1++;
}
#define gc() getch()
char qwq;
in int read()
{
re cz=0,ioi=1;qwq=gc();
while(qwq<'0'||qwq>'9') ioi=qwq=='-'?~ioi+1:1,qwq=gc();
while(qwq>='0'&&qwq<='9') cz=(cz<<3)+(cz<<1)+(qwq^48),qwq=gc();
return cz ak ioi;
}
const db inf=1e18,eps=1e-11;
const int N=1e5+5;
int n,m,k,top,tot;
db s,t;
struct poi{
db x,y;
poi(db _x=0,db _y=0) {x=_x,y=_y;}
}p[N];
struct line{
db k,b;
line(db _k=0,db _b=0) {k=_k,b=_b;}
in bool operator <(line x) const {return k==x.k?b>x.b:k<x.k;}
in poi operator &(line x) {return poi((x.b-b)/(k-x.k),(k*x.b-x.k*b)/(k-x.k));}
}e[N],q[N];
in db calc(re x) {return p[x].x*s+p[x].y*t;}
int main()
{
n=read();k=read();
for(re i=1;i<=n;i++)
{
db a=read(),b=read(),c=read();
e[++m]=line(-a/b,c/b);
}
sort(e+1,e+m+1);
for(re i=1;i<=m;i++)
{
if(top&&q[top].k==e[i].k) continue;
while(top>1&&(q[top]&q[top-1]).y<=(q[top]&q[top-1]).x*e[i].k+e[i].b) top--;
q[++top]=e[i];
}
for(re i=1;i<top;i++) p[++tot]=q[i]&q[i+1];
for(re i=1;i<=k;i++)
{
s=read(),t=read();
if(-s/t>q[top].k||-s/t<q[1].k) puts("IMPOSSIBLE");
else
{
db res=inf;re l=1,r=tot;
while(l<=r)
{
re ml=l+(r-l)/3,mr=r-(r-l)/3;
db cl=calc(ml),cr=calc(mr);
if(cl<cr) r=mr-1,res=cr;
else l=ml+1,res=cl;
}
printf("%.5lf\n",res);
}
}
}