「COCI 2019.1」Akvizna

题目链接 裸的\(\text{wqs}\)二分\(+\)斜率优化

二维\(\text{dp}\)的式子长这样:\(f[i][j]=\max\{f[k][j-1]+\frac{i-k}{i}\}\),答案就是\(f[n][k]\)

考虑\(\text{wqs}\)二分去掉\(k\)这一维,然后式子变成了\(f[i]=\max\{f[j]+\frac{i-j}{i}-val\}\),可以斜率优化了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,k,q[maxn],num[maxn];
double inv[maxn],f[maxn];
inline void calc(double val){
	int l,r;q[l=r=1]=0;
	for(int i=1;i<=n;i++){
		while(l<r&&q[l+1]-q[l]<=i*(f[q[l+1]]-f[q[l]]))l++;
		f[i]=f[q[l]]+1-q[l]*inv[i]-val;num[i]=num[q[l]]+1;
		while(l<r&&(f[q[r]]-f[i])*(q[r]-q[r-1])<=(f[q[r-1]]-f[q[r]])*(i-q[r]))r--;
		q[++r]=i;
	}
}
int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)inv[i]=1.0/i;
	double l=0,r=100,mid;
	for(int i=1;i<=50;i++){
		mid=(l+r)/2;
		calc(mid);
		if(num[n]>k)l=mid;
		else r=mid;
	}
	calc(l);
	printf("%.9lf\n",f[n]+k*l);
	return 0;
}
posted @ 2021-02-18 14:02  syzf2222  阅读(106)  评论(0编辑  收藏  举报