服务器

description

我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, …, Sn。首先,我们可以选择一些服务器,直接把文件复制到它们中;将文件复制到服务器Si上,需要花费ci > 0的置放费用。对于没有直接被复制文件的服务器Si来说,它依次向后检查Si+1, Si+2, …直到找到一台服务器Sj:Sj中的文件是通过直接复制得到的,于是Si从Sj处间接复制得到该文件,这种复制方式的读取费用是j – i(注意j>i)。另外,Sn中的文件必须是通过直接复制得到的,因为它不可能间接的通过别的服务器进行复制。我们设计一种复制方案,即对每一台服务器确定它是通过直接还是间接的方式进行复制(Sn只能通过直接方式),最终使每一台服务器都得到文件,且总花费最小。

solution

本题斜率优化板子吧,虽然维护错了...对于60分方程,我们可以令\(f[i][0]\)表示\(i\)这个点需要间连接的最小费用,\(f[i][1]\)表示\(i\)这个点直接连接的最小费用.不难得出转移方程为\(f[i][0]=min \{ f[j][1]+\frac{(j-i)\cdot (j-i+1)}{2} \},f[i][1]=min(f[i+1][0],f[i+1][1])+c[i]\).为方便转移,我们将此二者整合在一起\(F[i]\)表示\(i\)位置直接连接的dp值,则有\(F[i]=min\{ F[j]+\frac{(j-i)\cdot (j-i-1)}{2} \}+c[i]\),则\(f[0]\)即为答案.下面我们考虑优化:

\(F[j]+\frac{(j-i)\cdot(j-i-1)}{2}<F[k]+\frac{(k-i)\cdot(k-i-1)}{2}\)

\(\frac{F[j]-F[k]+\frac{(j^{2}-k^{2}-j+k)}{2}}{j-k}<i\);

将不等式左侧用\(g(j,k)\)表示,由于我们\(i\)递减,所以用单调队列维护递减的斜率,每次将i加入队列即可.

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<ctime>
#define R register
#define next kdjadskfj
#define debug puts("mlg")
#define Mod(x) ((x%mod+mod)%mod)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
inline ll read();
inline void write(ll x);
inline void writeln(ll x);
inline void writesp(ll x);
const ll maxn=1e6+10;
ll f[maxn][2];
ll n;
ll F[maxn];
ll c[maxn];
const ll inf=((ull)1<<63)-1;
inline double g(ll x,ll y){
	return (F[x]-F[y]+(x*x-y*y-x+y)/2.0)/(x-y);
}
inline void solve1(){
	f[n][1]=c[n];f[n][0]=inf;
	for(R ll i=n-1;i>=1;i--){
		f[i][1]=min(f[i+1][1],f[i+1][0])+c[i];
		f[i][0]=inf;
		for(R ll j=i+1;j<=n;j++){
			f[i][0]=min(f[i][0],f[j][1]+(((j-i)*(j-i+1))>>1));
		}
	}
	writeln(min(f[1][0],f[1][1]));
	exit(0);
}
ll q[maxn],l,r;
inline void solve2(){
	f[n][1]=c[n];f[n][0]=inf;
	F[n]=c[n];
	l=r=1;
	q[l]=n;
	for(R ll i=n-1;i>=0;i--){
		while(l<r&&g(q[l],q[l+1])>=i) ++l;
		F[i]=F[q[l]]+c[i]+(q[l]-i)*(q[l]-i-1)/2;
		while(l<r&&g(q[r-1],q[r])<g(i,q[r])) --r;
		q[++r]=i;
	}
	writeln(F[0]);
	exit(0);
}
int main(){
	freopen("server7.in","r",stdin);
	n=read();
	for(R ll i=1;i<=n;i++) c[i]=read();
	if(n<=1000) solve1();
	solve2();
}
inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;}
inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');}
inline void writesp(ll x){write(x);putchar(' ');}
inline void writeln(ll x){write(x);putchar('\n');}
posted @ 2020-08-14 15:06  月落乌啼算钱  阅读(109)  评论(0编辑  收藏  举报