#KTT#洛谷 9288 [ROI 2018] Innophone
题目
有一个二元函数 \(f(x,y)\),它是这么定义的:
\(f(x,y)=\left\{ \begin{array}{rcl} a, & & {\text{if} \quad \quad \ \ \ a \leq x}\\ b, & & {\text{else if} \quad b \leq y}\\ 0, & & {\text{else}} \end{array} \right.\)
其中 \(a,b\) 为常数。现在给定 \(n\) 组 \(x,y\),你需要选择合适的 \(a,b\),使得 \(\sum_{i=1}^{n} f(x_i,y_i)\) 最大。
分析
考虑将这 \(n\) 组 \(x,y\) 先按 \(x\) 从小到大排序,\(a\) 和 \(b\) 肯定分别是某个 \(x\) 以及某个 \(y\)。
固定 \(a\) 之后大于等于它的 \((x,y)\) 函数都是 \(a\),只需要考虑小于当前 \(a\) 的 \((x,y)\)。
如果选择了某个 \(b\),此时就是对大于等于 \(b\) 的 \(y\) 都能产生贡献,计个数为 \(x_c\),那么答案就是 \(bx_c+ma\)
可以发现答案是一个一次函数的形式甚至 \(ma\) 可以单独拎出来,而 \(x_c\) 只会越来越大,那么就可以用到 KTT。
将 \(y_i\) 离散化之后先查询,然后对 \(x_i=a\) 的 \([1,y_i]\) 整体加一,用 KTT 找到更优的截距,复杂度是三个 log 的。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N=150011;
typedef long long lll;
const lll inf=1e18;
lll ans=0;
int n,m,b[N]; pair<int,int>a[N];
struct Segment_Tree{
lll K[N<<2],B[N<<2],bound[N<<2],lazy[N<<2];
void pup(int k){
bound[k]=min(bound[k<<1],bound[k<<1|1]);
if (B[k<<1]<B[k<<1|1]||(B[k<<1]==B[k<<1|1]&&K[k<<1]<K[k<<1|1])){
K[k]=K[k<<1|1],B[k]=B[k<<1|1];
if (K[k<<1|1]<K[k<<1]) bound[k]=min(bound[k],(B[k<<1|1]-B[k<<1])/(K[k<<1]-K[k<<1|1]));
}else{
K[k]=K[k<<1],B[k]=B[k<<1];
if (K[k<<1]<K[k<<1|1]) bound[k]=min(bound[k],(B[k<<1]-B[k<<1|1])/(K[k<<1|1]-K[k<<1]));
}
}
void ptag(int k,lll z){
B[k]+=K[k]*z,lazy[k]+=z;
if (bound[k]!=inf) bound[k]-=z;
}
void pdown(int k){
if (lazy[k]){
ptag(k<<1,lazy[k]);
ptag(k<<1|1,lazy[k]);
lazy[k]=0;
}
}
void build(int k,int l,int r){
lazy[k]=0;
if (l==r){
K[k]=b[l],B[k]=0,bound[k]=inf;
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pup(k);
}
void update(int k,int l,int r,int x,int y,lll z){
if (l==x&&r==y&&z<=bound[k]){
ptag(k,z);
return;
}
int mid=(l+r)>>1;
pdown(k);
if (y<=mid) update(k<<1,l,mid,x,y,z);
else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
pup(k);
}
lll query(int k,int l,int r,int x,int y){
if (l==x&&r==y) return B[k];
int mid=(l+r)>>1;
pdown(k);
if (y<=mid) return query(k<<1,l,mid,x,y);
else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
else return max(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
}Tre;
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for (int i=1;i<=n;++i)
cin>>a[i].first>>a[i].second,b[i]=a[i].second;
sort(a+1,a+1+n),sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
for (int i=1;i<=n;++i)
a[i].second=lower_bound(b+1,b+1+m,a[i].second)-b;
Tre.build(1,1,m);
for (int l=1,r;l<=n;l=r+1){
ans=max(ans,1ll*(n-l+1)*a[l].first+Tre.query(1,1,m,1,m));
for (r=l;r<=n&&a[r].first==a[l].first;++r)
Tre.update(1,1,m,1,a[r].second,1);
--r;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号