bzoj4367-[IOI2014]holiday假期

Description

健佳正在制定下个假期去台湾的游玩计划。在这个假期,健佳将会在城市之间奔波,并且参观这些城市的景点。
在台湾共有n个城市,它们全部位于一条高速公路上。这些城市连续地编号为0到n-1。对于城市i(0 < i< n-1)而言,与其相邻的城市是i-1和i+1。但是对于城市 0,唯一与其相邻的是城市 1。而对于城市n-1,唯一与其相邻的是城市n-2。
每个城市都有若干景点。健佳有d天假期并且打算要参观尽量多的景点。健佳已经选择了假期开始要到访的第一个城市。在假期的每一天,健佳可以选择去一个相邻的城市,或者参观所在城市的所有景点,但是不能同时进行。即使健佳在同一个城市停留多次,他也不会去重复参观该城市的景点。请帮助健佳策划这个假期,以便能让他参观尽可能多的景点。

Input

第1行: n, start, d.
第2行: attraction[0], …, attraction[n-1].
n: 城市数。
start: 起点城市的编号。
d: 假期的天数。
attraction: 长度为n的数组;attraction[i] 表示城市i的景点数目,其中0≤i≤n-1。

Output

输出一个整数表示健佳最多可以参观的景点数。

Sample Input

5 2 7

10 2 20 30 1
Sample Output

60
HINT

假 设健佳有 7 天假期,有 5 个城市(参见下表),而且他由城市 2 开始。在第一天,健佳参观城市2的 20 个景点。第二天,健佳由城市 2 去往城市 3。而在第三天,健佳参观城市 3 的30 个景点。接下来的3天,健佳由城市 3 前往城市 0。而在第 7 天,健佳参观城市0的 10 个景点。这样健佳参观的景点总数是20+30+10=60,这是他由城市 2 开始、在 7 天假期内最多能参观的景点数目。

Source

鸣谢yts1999上传

Solution

课件:

容易发现最多拐一下, 再多就瘸了:P

用四个dp表示四种情况, 发现决策对于时间单调, 利用分治优化.

注意起点只能选一次!

Code

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,l,r) for(register int i=(l);i<=(r);++i)
#define repdo(i,l,r) for(register int i=(l);i>=(r);--i)
#define il inline
typedef double db;
typedef long long ll;

//---------------------------------------
const int nsz=1e5+50,dsz=3*nsz;
int n,st,d,line[nsz];

int *ptr[nsz],pp=0,inv[nsz],pi=0;
bool cmp(int *a,int *b){return (*a)<(*b);}
void uniq(){
	sort(ptr+1,ptr+pp+1,cmp);
	inv[pi]=-1;
	rep(i,1,pp){
		if((*ptr[i])!=inv[pi])inv[++pi]=*ptr[i];
		*ptr[i]=pi;
	}
}


struct tnd{int ch[2],cnt;ll sum;}tr[nsz*21];
#define ls(p) tr[p].ch[0]
#define rs(p) tr[p].ch[1]
#define tsum(p) tr[p].sum
#define tcnt(p) tr[p].cnt
int rt[nsz]{1},pt=1;

void insert(int v,int &rt,int rt0,int rl,int rr){
	rt=++pt,tr[rt]=tr[rt0];
	++tr[rt].cnt,tr[rt].sum+=(ll)inv[v];
	if(rl==rr)return;
	int mid=(rl+rr)>>1;
	if(v<=mid)insert(v,ls(rt),ls(rt0),rl,mid);
	else insert(v,rs(rt),rs(rt0),mid+1,rr);
}

ll qu(int k,int rt,int rt0,int rl,int rr){
	if(k<=0)return 0;
	if(k>=tcnt(rt)-tcnt(rt0))return tsum(rt)-tsum(rt0);
	if(rl==rr)return k*inv[rl];
	int mid=(rl+rr)>>1,rcnt=tcnt(rs(rt))-tcnt(rs(rt0));
	if(k<=rcnt)return qu(k,rs(rt),rs(rt0),mid+1,rr);
	else return tsum(rs(rt))-tsum(rs(rt0))+qu(k-rcnt,ls(rt),ls(rt0),rl,mid);
}

void pr(int rt,int rl,int rr){
	if(rt==0)return;
	printf("rt=%d rl=%d rr=%d cnt=%d sum=%lld ls=%d rs=%d\n",rt,rl,rr,tcnt(rt),tsum(rt),ls(rt),rs(rt));
	if(rl==rr)return;
	int mid=(rl+rr)>>1;
	pr(ls(rt),rl,mid);
	pr(rs(rt),mid+1,rr);
}
void pr(){
	rep(i,1,n){
		printf("i=%d\n",i);
		pr(rt[i],1,pi);
	}
}


ll f[2][2][dsz];//fl1: 0 straight; 1 turn back      fl2: 0 l; 1 r
void sol1(int fl1,int fl2,int l,int r,int dl,int dr){
	if(l>r||dl>dr)return;
	int mid=(l+r)>>1,used=0,pr=0;
	ll tmp,res=-1;
	rep(i,dl,dr){
		used=abs(i-st)*(fl1?2:1);
		int l=st+(fl1==0)*(fl2?1:-1),r=i;
		if(fl2==0)swap(l,r);
		if(mid<used||l>r)continue;
		tmp=qu(mid-used,rt[r],rt[l-1],1,pi);
		if(tmp>res)res=tmp,pr=i;
	}
	f[fl1][fl2][mid]=max(res,0ll);
	if(fl2){
		sol1(fl1,fl2,l,mid-1,dl,pr);
		sol1(fl1,fl2,mid+1,r,pr,dr);
	}
	else{	
		sol1(fl1,fl2,l,mid-1,pr,dr);
		sol1(fl1,fl2,mid+1,r,dl,pr);
	}
}

ll sol(){
	sol1(0,0,1,d,1,st-1);
	sol1(0,1,1,d,st+1,n);
	sol1(1,0,1,d,1,st);
	sol1(1,1,1,d,st,n);
	ll ans=0;
	rep(i,0,d){
		ans=max(ans,max(f[1][0][i]+f[0][1][d-i],f[1][1][i]+f[0][0][d-i]));
	}
	return ans;
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>st>>d;
	++st;
	rep(i,1,n)cin>>line[i],ptr[++pp]=&line[i];
	uniq();
	rep(i,1,n){
		insert(line[i],rt[i],rt[i-1],1,pi);
//		printf("i=%d\n",i);
//		pr(rt[i],1,pi);
	}
//	rep(i,1,pi)printf("%d ",inv[i]);
//	printf("\n");
//	pr();
	cout<<sol()<<'\n';
	return 0;
}
posted @ 2019-02-15 20:59  Ubospica  阅读(182)  评论(0编辑  收藏  举报