Loading [MathJax]/jax/element/mml/optable/BasicLatin.js

Luogu P5665 划分

MD今天和陈指导一起看了下觉得真是血妈简单,不过考场上还要写高精我估计就直接放弃了,现在肯定直接用__int128水了

fi,j表示上一次取的点是i,其对应的决策点为j的答案,显然fi,j=min

很显然我们可以把f_{i,j}看作一个f_i,设其最优决策点为pos_i,结合柯西不等式a^2+b^2<(a+b)^2我们容易发现这个转移具有决策单调性(猜都猜出来了),每个位置最右边的决策点是最优的

考虑用单调队列维护最右边的前驱,记pfx_i\sum_{j=1}^i a_j,若pfx_i-pfx_{q_{H+1}}\ge pfx_{q_{H+1}}-pfx_{pos_{q_{H+1}}}就可以移动前驱,移下项我们发现只要维护2\times pfx_i-pfx_{pos_i}单调递增即可

#include<bits/stdc++.h>
#define RI register int
#define CI const int&
#define calc(x) (2LL*pfx[x]-pfx[pos[x]])
using namespace std;
const int N=4e7+5,M=1e5+5;
int n,tp,m,x,y,z,b[N],l[M],r[M],p[M],q[N],pos[N]; long long pfx[N];
inline void write(__int128 x)
{
	if (x>9) write(x/10); putchar(x%10+'0');
}
int main()
{
	RI i,j; scanf("%d%d",&n,&tp); if (!tp)
	for (i=1;i<=n;++i) scanf("%d",&x),pfx[i]=pfx[i-1]+x; else
	{
		scanf("%d%d%d%d%d%d",&x,&y,&z,&b[1],&b[2],&m);
		for (i=3;i<=n;++i) b[i]=(1LL*x*b[i-1]+1LL*y*b[i-2]+z)&((1<<30)-1);
		for (i=1;i<=m;++i) scanf("%d%d%d",&p[i],&l[i],&r[i]);
		for (i=j=1;j<=m;++j) while (i<=p[j])
		pfx[i]=pfx[i-1]+b[i]%(r[j]-l[j]+1)+l[j],++i;
	}
	RI H=1,T=1; for (i=1;i<=n;++i)
	{
		while (H<T&&calc(q[H+1])<=pfx[i]) ++H; pos[i]=q[H];
		while (H<T&&calc(q[T])>calc(i)) --T; q[++T]=i;
	}
	__int128 ans=0; for (i=n;i;i=pos[i])
	ans+=(__int128)(pfx[i]-pfx[pos[i]])*(pfx[i]-pfx[pos[i]]);
	return write(ans),0;
}
posted @   空気力学の詩  阅读(136)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示