把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P6246 [IOI2000] 邮局 加强版

题面传送门
知道结论这个就很水了。
因为这个如果这个东西前面能划分掉一定不会等到最后划分所以一定是个凸函数。
然后直接wqs二分分一下然后决策单调性乱划即可。
时间复杂度\(O(nlognlogw)\)不过感觉还跑得很快,最大点才700ms直接最优解。
code:

#include <vector>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 500000
#define eps (1e-6)
#define mod 1000000007
using namespace std;
int n,m,k,x,y,z,head,tail;ll dp[N+5],l,r,mid,g[N+5],sum[N+5];
I ll calc(int x,int y){return sum[y]+sum[x-1]-sum[x+y>>1]-sum[x+y-1>>1];}
struct ques{int l,r,id;}q[N+5];
I int check(ll k){
	re int i,j,l,r,mid;q[head=tail=0]=(ques){1,n,0};
	for(i=1;i<=n;i++){
		while(head<=tail&&q[head].r<i) head++;j=q[head].id;dp[i]=dp[j]+calc(j+1,i)-k;g[i]=g[j]+1;
		while(head<=tail&&(q[tail].l=max(q[tail].l,i))&&dp[q[tail].id]+calc(q[tail].id+1,q[tail].l)>=dp[i]+calc(i+1,q[tail].l)) tail--;
		if(head>tail){q[++tail]=(ques){i,n,i};continue;}l=q[tail].l;r=q[tail].r+1;
		while(l+1<r)mid=l+r>>1,(dp[q[tail].id]+calc(q[tail].id+1,mid)<dp[i]+calc(i+1,mid))||(dp[q[tail].id]+calc(q[tail].id+1,mid)==dp[i]+calc(i+1,mid)&&g[i]<g[q[tail].id])?(l=mid):(r=mid);
		q[tail].r=l;if(r<=n) q[++tail]=(ques){r,n,i};
	}
	return g[n]>=m;
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&sum[i]),sum[i]+=sum[i-1];l=-1e9;r=0;
	while(l+1<r)mid=l+r>>1,(check(mid)?r:l)=mid;check(r);printf("%lld\n",dp[n]+r*m);
}
posted @ 2021-05-25 19:31  275307894a  阅读(72)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end