BZOJ 5424: 烧桥计划

BZOJ 5424: 烧桥计划

目前暂居rk1QAQ

首先,设\(f[i][k]\)为前i个点中,选了第i个点,总共选了k个点的答案。那么就有:

\[f[i][k]=min_{j<i}\{f[j][k-1]+calc(j,i)\}+k*a[i] \]

其中,\(calc(j,i)=[s[i-1]-s[j]>m]*(s[i-1]-s[j])\)

那么转移的时候,大于m的很显然的可以用前缀和,而小于等于m的可以用单调队列处理。这样转移复杂度就变成了\(O(n^2)\)

\(1000 \le a_i\le 2000\),那么就设选的最小的k个点,k个点的贡献就是\(\frac{k*(k-1)}{2}1000\),而如果一个点也不选,那么贡献最大是\(2000n\),可以发现,当\(k\ge \sqrt{n}\)的时候,选一定不会更优了,所以只需要转移大约\(\sqrt n\)次就好了。

然后转移151次会WA,而转移152次就能A掉了,所以。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vi vector<int>
#define vit vector<int>::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) (sort(x,y),reverse(x,y))
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=110000;
const int inf=0x3f3f3f3f;

int n,m,a[Maxn],s[Maxn],f[Maxn],l,r,cur,g[Maxn];
pir p[Maxn];

void push(int x,int y) {
	pir now=mp(x,y);
	while(r>=l&&p[r]>now) r--;
	p[++r]=now;
}

int front() {
	while(p[l].sc<cur) l++;
	return p[l].fr;
}

signed main() {
//	freopen("test.in","r",stdin);
	read(n,m);
	if(m<0) m=0;
	for(int i=1;i<=n;i++)
		read(a[i]);
	n++;
	for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
	int ans=inf,cnt=1;
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++) g[i]=s[i];
//	memset(g,0x3f,sizeof(g));
//	for(int i=1;i<=n;i++) f[i]=g[i]=inf;
	for(int i=1;i<=152;i++) {
		r=0,l=1;
		cur=0;
		push(0,0);
		int temp=inf;
		for(int i=1;i<=n;i++) {
			while(s[i-1]-s[cur]>m) qmin(temp,g[cur]-s[cur]),cur++;
			int sxz=f[i];
			f[i]=s[i-1]+temp;
			qmin(f[i],front());
			push(sxz,i);
			f[i]+=cnt*a[i];
		}
		qmin(ans,f[n]);
		memcpy(g,f,sizeof(g));
		cnt++;
	}
	printf("%d\n",ans);
	return 0;
}



posted @ 2019-03-09 18:43  shanxizeng  阅读(492)  评论(0编辑  收藏  举报
广告位招商,有意者请联系