题目描述如下:

经过几个月辛勤的工作,FJ 决定让奶牛放假。假期可以在 1…N 天内任意选择一段(需要连
续),每一天都有一个享受指数 W。但是奶牛的要求非常苛刻,假期不能短于 P 天,否则奶
牛不能得到足够的休息;假期也不能超过 Q 天,否则奶牛会玩的腻烦。FJ 想知道奶牛们能
获得的最大享受指数。
Input(holiday.in)
第一行:N,P,Q.
第二行:N 个数字,中间用一个空格隔开。
Output(holiday.out)
一个整数,奶牛们能获得的最大享受指数。
Sample Input
5 2 4
-9 -4 -3 8 -6
Sample Output
5
Limitation
time:1s
memory:65536kb
50% 1≤N≤10000
100% 1≤N≤100000
1<=p<=q<=n
Hint
选择第 3-4 天,享受指数为-3+8=5。

这道题当时看的时候大概想了5分钟左右吧……结合最近学的RMQ和线段树。因为我们要求一段连续区间和的最大值,我们可以想到首先必然要枚举这个假期开始的日期,之后你的起始点确定,终点必然在[i+p-1,i+q-1]这段区间之内。这样的话其实范围就相对确定了,对于一段区间的和,我们可以先手初始化前缀和之后以相减的方法求出,而最关键的位置就在于如何确定终点?因为我们要求最大值,而前面一段区间的前缀和已经被确定,所以只要在[i+p-1,i+q-1]中找出前缀和最大值即可。而每段区间的最大值完全可以用线段树或者st表维护。这样就可以解决这个问题了。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n') typedef long long ll;
using namespace std;
const int M = ;
struct seg
{
int v;
}t[M<<];
ll n,p,q,a[M],maxn;
bool flag;
ll read()
{
ll ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} void build(ll p,ll l,ll r)
{
if(l == r)
{
t[p].v = a[l];
return;
}
ll mid = (l+r) >> ;
build(p<<,l,mid);
build(p<<|,mid+,r);
t[p].v = max(t[p<<].v,t[p<<|].v);
} ll query(int p,int l,int r,int kl,int kr)
{
if(l == kl && r == kr)
{
return t[p].v;
}
ll mid = (l+r) >> ;
if(kr <= mid) return query(p<<,l,mid,kl,kr);
else if(kl > mid) return query(p<<|,mid+,r,kl,kr);
else return max(query(p<<,l,mid,kl,mid),query(p<<|,mid+,r,mid+,kr));
} int main()
{
// freopen("holiday.in","r",stdin);
// freopen("holiday.out","w",stdout);
n = read(),p = read(),q = read();
rep(i,,n) a[i] = read(),a[i] += a[i-];
build(,,n);
rep(i,,n)
{
ll dl = i*1ll+p-,dr = i*1ll+q-;
if(dl > n) break;
if(dr > n) dr = n;
ll k = query(,,n,dl,dr) - a[i-];
if(!flag) maxn = k,flag = ;
else maxn = max(maxn,k);
}
printf("%lld\n",maxn);
return ;
}
/*
5 2 4
-9 -4 -3 8 -6
*/

这段代码的时间复杂度是O(nlogn),有没有更好的做法?

有!因为我们在上面的做法中是维护最大值然后减前缀和,那么我们同样可以用前缀和去减前面的最小值!即f[i] = sum[i] - min(sum[1…i])。那么我们可以用单调队列来维护一个单调递增的序列之后每次用当前的值去减队首元素(最小值)即可。

这样的话由于每个点都进入队列一次,所以一共出队列必然<=n次,时间复杂度是O(n),最多不过O(2*n).

看一下代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<queue>
#include<vector>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
typedef long long ll;
using namespace std;
const int M = ;
ll a, n, p, Q, head = , tail, q[M], f[M], sum[M], ans = -0X3f3f3f3f;
int main()
{
scanf("%lld %lld %lld", &n, &p, &Q);
rep(i,,n) scanf("%lld", &a),sum[i] = a + sum[i-];
rep(i,p,n)
{
while(sum[q[tail]] >= sum[i-p] && head <= tail) tail--;//因为i-p处的元素必须入队,所以队中一切比sum[i-p]大的元素必须出队
q[++tail] = i - p;//把sum[i-p]压入队列
while(q[head] < i - Q) head++;//因为我们最多只能取到i-q这么长的区间,所以在这个区间之前的所有元素必须出列。
f[i] = sum[i] - sum[q[head]];
ans = max(ans, f[i]);
}
printf("%lld\n", ans);
return ;
}

holiday题解的更多相关文章

  1. holiday(假期)_题解

    holiday(假期) —— 一道妙题(codevs3622)   Description 经过几个月辛勤的工作,FJ 决定让奶牛放假.假期可以在1…N 天内任意选择一段(需要连续),每一天都有一个享 ...

  2. hdoj 1827 Summer Holiday【强连通分量&&缩点】

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  3. Summer Holiday(强联通入度最小点)

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  4. 【BZOJ4367】[IOI2014]holiday假期 分治+主席树

    [BZOJ4367][IOI2014]holiday假期 Description 健佳正在制定下个假期去台湾的游玩计划.在这个假期,健佳将会在城市之间奔波,并且参观这些城市的景点.在台湾共有n个城市, ...

  5. Tarjan & LCA 套题题目题解

    刷题之前来几套LCA的末班 对于题目 HDU 2586 How far away 2份在线模板第一份倍增,倍增还是比较好理解的 #include <map> #include <se ...

  6. ZOJ 3876 May Day Holiday 蔡勒公式

                                                   H - May Day Holiday Description As a university advoc ...

  7. 【codeforces 758A】Holiday Of Equality

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  8. 洛谷 P2921 在农场万圣节Trick or Treat on the Farm题解

    题意翻译 题目描述 每年,在威斯康星州,奶牛们都会穿上衣服,收集农夫约翰在N(1<=N<=100,000)个牛棚隔间中留下的糖果,以此来庆祝美国秋天的万圣节. 由于牛棚不太大,FJ通过指定 ...

  9. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

随机推荐

  1. ZOJ 1112 Dynamic Rankings【动态区间第K大,整体二分】

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题意: 求动态区间第K大. 分析: 把修改操作看成删除与增加 ...

  2. idea修改变量及其引用

    idea 修改某一变量及其引用 选中变量 shift+f6(shift+fn+f6), ctrl+R的当前页面全局替换, ctrl+shift+R 项目中的全局替换

  3. mysql中进行删除操作时用到not in 导致删除不成功

    delete from tb_news where id not in ( select max(id) From tb_news Group By title ) 刚开始用这条语句删除一直不成功 然 ...

  4. MFC中的双缓冲技术(解决绘图闪烁问题)

    转自 MFC绘图不闪烁——双缓冲技术[转] 在VC/MFC用CDC绘图时,频繁的刷新,屏幕会出现闪烁的现象,CPU时间占用率相当高,绘图效率极低,很容易出现程序崩溃. 所谓双缓冲技术,下面是百度百科的 ...

  5. Oracle SQL Developer Chanage UI to US Lanaguage

    \sqldeveloper-4.1.3.20.78-x64\sqldeveloper\sqldeveloper\bin Add content: AddVMOption -Duser.country= ...

  6. 【kotlin】报错 Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type List<String>?

    报错如下: 解决如下: 另一种情况: 解决如下:

  7. 源码编译安装php

    原文:https://klionsec.github.io/2017/11/23/phpsec/#menu After compile install php 5.3.1, I can not fin ...

  8. 多线程网页爬虫 python 实现

    采用了多线程和锁机制,实现了广度优先算法的网页爬虫. 对于一个网络爬虫,如果要按广度遍历的方式下载,它就是这样干活的:         1.从给定的入口网址把第一个网页下载下来         2.从 ...

  9. Network Booting

    http://en.wikipedia.org/wiki/Network_booting Network booting Network booting is the process of booti ...

  10. iGrimaceVX3.0和1.44在线源手机直接安装教程

    [第一步] 先安装好三个组件设备必须是苹果越狱好后 确定6点几跟7点几的版本号才干够 首先打开cydia 选开发人员 以下 点软件源 点右上角编辑  1加入源 apt.25pp.com和IG包下载源a ...