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;
}