题目描述如下:

经过几个月辛勤的工作,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. 关于xshell无法连接到centos的问题

    1.xshell无法连接到centos:拒绝连接(无线网) 在xshell ping centos出现: 解决方法: 1. 2.重启下网卡: [root@localhost ~]# /etc/init ...

  2. Codechef Yet another cute girl

    题意大概就是让你求一下[L,R]中的约数个数是素数的数的个数. 其中1<=L<=R<=1e12,R-L<=1e6. 然后我写了两种做法,第一种是可以直接搞出来L-R的约数个数, ...

  3. 9.Java web—JSP内置对象

    容器内置了9大对象,这些对象在jsp页无需实例化,可以直接使用. 分别为request. response .session. application .out. pageContext .confi ...

  4. ssh 卡主

    偶尔会遇到这样的现象 ssh 登录一台远程机器,显示下面的信息然后hang在那 Connecting to 192.168.137.102:22... Connection established. ...

  5. python之入门,你好,中国

    print("你好,中国") 可以运行py文件实现一样的效果(py文件编码一定要是utf-8编码) 你好中国基础教程结束!

  6. HTML--比较实用的小例子

    常用的前端实例: 1略 2.在网页商城中的图片当我们把鼠标放上去之后,图片会显示一个有颜色的外边框,图片某一部分的字体的颜色并发生改变 鼠标放上去之前 鼠标放上去之后: 实现的代码: <!DOC ...

  7. Flex4_操作XML

    一.创建XML类 1.把字符串对象转换为XML: var xmlStr:String="<students><student><name>吕布</n ...

  8. v-for指令

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. Sublime Text2-Control Package---ShinePans

    1.打开sublime Text2 2.菜单条中的preference>>BrowsePackages 3.退到上一级打开Installed Packages 4.拷贝文件到此目录 (Pa ...

  10. vue 安装与起步

    vue安装: 1.官网下载vue,在script标签里引用(去下载) 2.使用CDN(建议下载到本地,不推荐这种方法): BootCDN:https://cdn.bootcss.com/vue/2.2 ...