首页 > 其他分享 >luogu P1721 [NOI2016] 国王饮水记

luogu P1721 [NOI2016] 国王饮水记

时间:2022-08-18 08:11:23浏览次数:97  
标签: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
From: https://www.cnblogs.com/275307894a/p/16597470.html

相关文章

  • luogu P8293 [省选联考 2022] 序列变换
    题面传送门因为WC2022考了这种构造,所以下意识将括号序列建树。手玩一下发现第一个操作实际上是干了这个事情:也就是说把用其中一个括号将另一个同层括号在树上移到了下......
  • luoguP3521 [POI2011]ROT-Tree Rotations【线段树】
    你要写热,就不能只写热。要写酷暑,写骄阳,写他人耳闻便生恐的炙烤和炎灼。要写白日出门一刻便肤色黝黑,背心透彻。写求雨心切,写出行伞遮。写夜晚不停的风扇和蝉聒。写鸡......
  • luoguP3224 [HNOI2012]永无乡【线段树,并查集】
    洞庭青草,近中秋,更无一点风色。玉鉴琼田三万顷,着我扁舟一叶。素月分辉,明河共影,表里俱澄澈。悠然心会,妙处难与君说。应念岭表经年,孤光自照,肝胆皆冰雪。短发萧骚襟袖冷,稳泛......
  • 【luogu CF1710C】XOR Triangle(数位DP)
    XORTriangle题目链接:luoguCF1710C题目大意给你一个数n,要你求有多少个满足条件的a,b,c使得它们两两异或得到的三个值可以得到一个非退化三角形。其中a,b,c值域在......
  • 【$dp$】$\text{LuoguP6570}$ 优秀子序列
    \(\text{LuoguP6570}\)优秀子序列读完题大概能yy到一个转移,即枚举两个不相交的子集然后转移。其实这题的顺序都无所谓,应该排个序,或者直接在值域上操作。\(DP\),用\(f......
  • 【luogu CF1710B】Rain(差分)(性质)
    Rain题目链接:luoguCF1710B题目大意给你若干个函数,每个函数是一个45度往上线段和往下线段接在一起,两个长度一样,y轴从0出发的。然后对于每个函数,求把它以外的所有......