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上传

首先我们考虑这样一个问题,如果给定健佳访问的城市区间,如何计算他最多能参观的景点数量。

我们发现这个问题在可持久化线段树上二分一下就可以解决了。

那么我们重新考虑这个问题,我们发现随着右端点的递增,左端点也是递增的,这样的决策单调性让我们联想到NOI2009诗人小G的做法。

设calc(x,y)表示左端点为x比左端点为y劣的最小右端点r,这个可以很容易通过二分套之前的算法解决。

我们维护决策序列Q,当新的决策x加入时,如果calc(Q[r-1],Q[r])>=calc(Q[r],x),那么Q[r]就是没有用的决策,因为Q[r]永远不可能成为最优决策。

那么这个问题就在O(Nlog^2N)的时间里解决了。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
	if(head==tail) {
		int l=fread(buffer,1,BufferSize,stdin);
		tail=(head=buffer)+l;
	}
	return *head++;
}
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
typedef long long ll;
const int maxn=100010;
const int maxnode=2000010;
int n,S,d,A[maxn],tmp[maxn];
ll sumv[maxnode];
int root[maxn],s[maxnode],ls[maxnode],rs[maxnode],ToT;
void build(int& y,int x,int l,int r,int p) {
	s[y=++ToT]=s[x]+1;sumv[y]=sumv[x]+tmp[p];if(l==r) return;
	int mid=l+r>>1;ls[y]=ls[x];rs[y]=rs[x];
	if(p<=mid) build(ls[y],ls[x],l,mid,p);
	else build(rs[y],rs[x],mid+1,r,p);
}
ll query(int y,int x,int l,int r,int k) {
	if(l==r) return (ll)min(s[y]-s[x],k)*tmp[l];
	int mid=l+r>>1;
	if(s[rs[y]]-s[rs[x]]>=k) return query(rs[y],rs[x],mid+1,r,k);
	return query(ls[y],ls[x],l,mid,k-s[rs[y]]+s[rs[x]])+sumv[rs[y]]-sumv[rs[x]];
}
ll solve(int l,int r) {
	int w=r-l+min(r-S,S-l);
	if(d<=w) return 0;
	return query(root[r],root[l-1],1,n,min(r-l+1,d-w));
}
int calc(int x,int y) {
	int l=S,r=n+1;
	while(l<r) {
		int mid=l+r>>1;
		if(solve(x,mid)<=solve(y,mid)) r=mid;
		else l=mid+1;
	}
	return l;
}
int Q[maxn],g[maxn];
int main() {
	n=read();S=read()+1;d=read();
	rep(i,1,n) A[i]=tmp[i]=read();
	sort(tmp+1,tmp+n+1);
	rep(i,1,n) A[i]=lower_bound(tmp+1,tmp+n+1,A[i])-tmp;
	rep(i,1,n) build(root[i],root[i-1],1,n,A[i]);
	int l=1,r=0;
	rep(i,1,S) {
		while(l<r&&g[r-1]>=calc(Q[r],i)) r--;
		Q[++r]=i;if(l<r) g[r-1]=calc(Q[r-1],Q[r]);
	}
	ll ans=0;
	rep(i,S,n) {
		while(l<r&&solve(Q[l],i)<=solve(Q[l+1],i)) l++;
		ans=max(ans,solve(Q[l],i));
	}
	printf("%lld\n",ans);
	return 0;
}

  

时间: 2024-10-18 11:49:13

BZOJ4367: [IOI2014]holiday假期的相关文章

IOI2014题解

这个东西还是应该写写博客的,毕竟IOI 题目连接已给出,直接点击大标题(推荐网络OJ:Universal Online Judge) IOI2014 Rail 题目有点难看,耐心-- 题目是说给出任意两段车站的距离(你只能得知其中的3(n?1)对距离)和0车站的位置,让你确定每个车站的位置和类型C或D 距离的定义请看题 题目保证0车站为C类型 直接说正确的解法(部分分很水请独立思考) 我们会发现: 1.车站x到y的距离==车站y到x的距离 2.离距离某个C类型车站最近的车站一定是右方向上最近的D

words2

餐具:coffee pot 咖啡壶coffee cup 咖啡杯paper towel 纸巾napkin 餐巾table cloth 桌布tea -pot 茶壶tea set 茶具tea tray 茶盘caddy 茶罐dish 碟plate 盘saucer 小碟子rice bowl 饭碗chopsticks 筷子soup spoon 汤匙knife 餐刀cup 杯子glass 玻璃杯mug 马克杯picnic lunch 便当fruit plate 水果盘toothpick 牙签中餐:bear's

退役前的做题记录5.0

退役前的做题记录5.0 出于某种原因新开了一篇. [CodeChef]Querying on a Grid 对序列建立分治结构,每次处理\((l,mid,r)\)时,以\(mid\)为源点建立最短路树,这样跨越\(mid\)的点对之间的最短路一定会经过\(mid\),因此两点之间的最短路径就可以描述成最短路树上的两段到根路径.对每棵最短路树处理\(dfs\)序,用树状数组维护权值修改即可. [Wannafly挑战赛4F]线路规划 类似SCOI2016萌萌哒一题,并查集\(f_{i,j}\)表示从

uoj#29. 【IOI2014】Holiday

http://uoj.ac/problem/29 经过的点集一定是一个包含start的区间,为了经过这个区间内所有点,必须先到达一个区间端点,再到达另一个区间端点,剩余的步数则贪心选区间内最大价值的点.显然决策单调,于是可以分治,用可持久化线段树快速求出区间前k大数之和. #include"holiday.h" #include<cstring> #include<algorithm> typedef long long i64; const int N=500

ZOJ 3876 May Day Holiday 蔡勒公式

                                               H - May Day Holiday Description As a university advocating self-learning and work-rest balance, Marjar University has so many days of rest, including holidays and weekends. Each weekend, which consists o

请假时碰到法定假期,实际请假几天?

去面试,问了一个问题: 员工请假了几天,刚好这几天与法定节假日有重合,那么法定节假日那几天就不算请假,请问重合的天数有几天(或者说实际请假几天) 让在白板上写代码,居然脑子也白了…… 一出门就清醒了,方案就出来,可惜晚了 require 'date' #方法一,通过间断节假日是否在请假区间内,计算出与节假日重合的开始和结束日期 def calc_date(holiday_start,holiday_end, leave_start, leave_end) holiday_region = hol

Python工作日类库Busines Holiday介绍

引言: 在日常工作中.常常会碰到相似的场景.须要计算在某个时间段内的工作日以及确定某天是否为工作日,这里的介绍的工具包将很好的解决问题. 1. 工具包Business Holiday介绍 其提供了很easy易用的计算工作日的接口.并同意用户指定特定日期为假期,从而将其从当前的工作日中剔除. 项目主页: https://pypi.python.org/pypi/business_calendar/ 文档首页: http://py-business-calendar.readthedocs.io/e

OJ 1159 holiday

From easthong☆holiday 描述 Description 经过几个月辛勤的工作,FJ决定让奶牛放假.假期可以在1-N天内任意选择一段(需要连续),每一天都有一个享受指数W.但是奶牛的要求非常苛刻,假期不能短于P天,否则奶牛不能得到足够的休息:假期也不能超过Q天,否则奶牛会玩的腻烦.FJ想知道奶牛们能获得的最大享受指数. 输入格式 Input Format 第一行:N,P,Q. 第二行:N个数字,中间用一个空格隔开. 输出格式 Output Format 一个整数,奶牛们能获得的最

holiday题解

题目描述如下: 经过几个月辛勤的工作,FJ 决定让奶牛放假.假期可以在 1-N 天内任意选择一段(需要连续),每一天都有一个享受指数 W.但是奶牛的要求非常苛刻,假期不能短于 P 天,否则奶牛不能得到足够的休息:假期也不能超过 Q 天,否则奶牛会玩的腻烦.FJ 想知道奶牛们能获得的最大享受指数.Input(holiday.in)第一行:N,P,Q.第二行:N 个数字,中间用一个空格隔开.Output(holiday.out)一个整数,奶牛们能获得的最大享受指数.Sample Input5 2 4