ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luogu P1721 [NOI2016] 国王饮水记

2022-08-18 08:32:28  阅读:135  来源: 互联网

标签:frac luogu st NOI2016 dp using 节点 P1721 define


题面传送门

首先我们发现,一定不会有低于\(h_1\)的参与操作的过程。

然后考虑一个\(x\)与比它大的\(y<z\),则发现一定是先\((x,y)\),再\((\frac{x+y}{2},z)\)更好。

因为这样是\(\frac{4}{x+y}+\frac{z}{2}\),而一起做是\(\frac{x+y+z}{3}\),显然更优。

而每个节点一定只会和一号节点联通一次,因为如果联通过了那么肯定小于等于一号节点了。这里可以把\(k=\min(k,n)\)。

且每次操作一定包含一号节点,因为如果不包括一号节点相当于缩小了两个之间的差距,则会使其变小。

同时考虑,如果两次相邻操作之间范围有交,那么交换使得范围无交显然更优。并且如果两次之间有剩余的点,那么并入较小的一次会更优。

因此我们可以写出一个\(O(n^3p)\)的dp:设\(dp_{i,j}\)表示到了第\(i\)次,划分到从小到大第\(j\)个,\(1\)号的最大值。转移方程\(dp_{i,j}=\max\limits_{k=1}^{j-1}{\frac{dp_{i-1}{k}+Sum_j-Sum_k}{j-k+1}}\)。

容易发现这是一个斜率的形式,因此可以以每个点\((j-1,sum_j-dp_{i}{j})\)构建凸壳,然后每个询问点在凸壳上查找斜率最大点可以做到\(O(n^2\log np)\)。进一步的,因为\(\frac{Sum_i}{i}\)单调递增,因此和原点连线斜率递增。故可以决策单调性去掉三分,时间复杂度\(O(n^2p)\)。

观察到我们的时间消耗在dp过程中的高精度小数上,如果能每次求出最优转移点,然后最后再用高精度小数计算即可。过程中可以用一个double计算转移,根据出题人题解,是有理有据地精度不会爆,因此将时间复杂度降至\(O(n(n+p))\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
#undef continue
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=8e3+5,M=1<<16|5,K=10000+5,mod=998244353,Mod=mod-1;const db eps=1e-5;
int n,m,k,p,x,Q[N],B[N],Bh,st[N],H,T;Decimal Ans;db f[N],g[N];short La[N][N];
db slope(int x,int y){return (Q[y]-g[y]-Q[x]+g[x])/(y-x);}
int main() {
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j,h;scanf("%d%d%d",&n,&k,&p);for(i=1;i<=n;i++) scanf("%d",&Q[i]);sort(Q+2,Q+n+1);k=min(k,n-1);for(i=1;i<=n;i++) Q[i]+=Q[i-1];
	for(i=1;i<=n;i++)f[i]=Q[1];for(i=1;i<=k;i++){Mc(g,f);Me(f,0); 
		st[H=T=0]=1;for(j=2;j<=n;j++){
			//for(h=H;h<=T;h++) (g[st[h]]+Q[j]-Q[st[h]])/(j-st[h]+1)>f[j]&&(f[j]=(g[st[h]]+Q[j]-Q[st[h]])/(j-st[h]+1),La[i][j]=st[h]);
			while(H^T&&(g[st[H]]+Q[j]-Q[st[H]])/(j-st[H]+1)<(g[st[H+1]]+Q[j]-Q[st[H+1]])/(j-st[H+1]+1)) H++;
			La[i][j]=st[H];f[j]=(Q[j]-Q[st[H]]+g[st[H]])/(j-st[H]+1);f[j]<g[j]&&(f[j]=g[j],La[i][j]=j);
			while(H^T&&slope(st[T-1],st[T])>slope(st[T],j)) T--;st[++T]=j;
			//for(h=1;h<j;h++) (g[h]+Q[j]-Q[h])/(j-h+1)>f[j]&&(f[j]=(g[h]+Q[j]-Q[h])/(j-h+1),La[i][j]=h);
		}
	}x=n;for(i=k;i;i--) B[++Bh]=x,x=La[i][x];B[++Bh]=x;Ans=Q[1];for(i=k;i;i--) Ans=(Ans+Q[B[i]]-Q[B[i+1]])/(B[i]-B[i+1]+1);
	cout<<Ans.to_string(2*p)<<'\n';
}

标签:frac,luogu,st,NOI2016,dp,using,节点,P1721,define
来源: https://www.cnblogs.com/275307894a/p/16597470.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有