题目描述如下:

经过几个月辛勤的工作,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. MySQL与MSSQL的一些语法差异(持续更新中)

    分号不能少:分号不能少:分号不能少:重要的事情说3遍 Insert或者Update的数据包含反斜杠\的时候需要进行转义\\,例:insert into tablename(id,name) value ...

  2. P3367 并查集【模板】 洛谷

    https://www.luogu.org/problem/show?pid=3367#sub 题目描述 如题,现在有一个并查集,你需要完成合并和查询操作. 输入输出格式 输入格式: 第一行包含两个整 ...

  3. Thrift --- 支持双向通信

    [问题] Thrift采用了C/S模型,不支持双向通信:client只能远程调用server端的RPC接口,但client端则没有RPC供server端调用,这意味着,client端能够主动与serv ...

  4. C#中值类型和引用类型的差别浅记

    C#中值类型和引用类型的差别浅记         在C#中,变量的类型分为两种.各自是值类型和引用类型.         值类型的变量直接存储值,说得更详细一些,就是值类型变量在内存中直接存储它们自身 ...

  5. 取汉子拼音首字母的VB.Net方法

    '/ <summary> '/ 获得一个字符串的汉语拼音码 '/ </summary> '/ <param name="strText">字符串 ...

  6. [React] Use React.memo with a Function Component to get PureComponent Behavior

    A new Higher Order Component (HOC) was recently released in React v16.6.0 called React.memo. This be ...

  7. PHPMailer发送邮件乱码

    PHPMailer发送邮件乱码, $mail->CharSet="GB2312";$mail->Encoding = "base64"; 设成这样不 ...

  8. Struts拦截器(转)

    xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC &qu ...

  9. Codeforces Round #335 (Div. 2) 606B Testing Robots(模拟)

    B. Testing Robots time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  10. 翻译:A Tutorial on the Device Tree (Zynq) -- Part II

    A Tutorial on the Device Tree (Zynq) -- Part II 设备树结构 Zynq的设备树如下: /dts-v1/; / { #address-cells = < ...