题目描述

共有\(m\)部电影,编号为\(1——m\),第\(i\)部电影的好看值为\(w[i]\)。在\(n\)天之中(从\(1~n\)编号)每天会放映一部电影,第\(i\)天放映的是第\(f[i]\)部。你可以选择\(l,r(1 \leq l \leq r \leq n)\),并观看第\(l,l+1,…,r\)天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。

输入输出格式

输入格式:

第一行两个整数\(n,m(1 \leq m \leq n \leq 1000000)\)。第二行包含\(n\)个整数\(f[1],f[2],…,f[n]\)。第三行包含\(m\)个整数\(w[1],w[2],…,w[m]\)。

输出格式:

输出观看且仅观看过一次的电影的好看值的总和的最大值。

输入输出样例

输入样例#1:

9 4
2 3 1 1 4 1 2 4 1
5 3 6 6

输出样例#1:

15

思路:这道题目我们可以考虑先记录每种电影上一次开播时间和下一次开播时间(即以下代码中的\(last\)数组和\(nxt\)数组),然后对于每种电影,我们可以先处理中它是否播放过对后面区间的影响情况,然后再对\(n\)个时间点分别考虑,我们可以枚举左端点,然后根据左端点电影的播放情况就可以确定它可以影响到的最右端点,然后不断更新,更新过程中记录最大值,最后那个最大值即为答案。

洛谷P3582(自己写的题解)

代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#define ll long long
#define maxn 1000007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
int n,m,f[maxn],nxt[maxn],last[maxn],a[maxn];
ll ans;
inline int qread() { //快读,不解释……
char c=getchar();int num=0,f=1;
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) num=num*10+c-'0';
return num*f;
}
struct Tree {
ll maxx,lazy;
}tree[maxn<<2];
inline void pushdown(int rt) { //下放lazy标记。
if(tree[rt].lazy) {
tree[ls].lazy+=tree[rt].lazy;
tree[rs].lazy+=tree[rt].lazy;
tree[rs].maxx+=tree[rt].lazy;
tree[ls].maxx+=tree[rt].lazy;
tree[rt].lazy=0;
}
}
void modify(int rt,int l,int r,int L,int R,int val) { //区间修改,用于后面的更新。
if(L>r||R<l) return;
if(L<=l&&r<=R) {
tree[rt].lazy+=val;
tree[rt].maxx+=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
tree[rt].maxx=max(tree[ls].maxx,tree[rs].maxx);
}
int main() {
n=qread(),m=qread();
for(int i=1;i<=n;++i) f[i]=qread();
for(int i=1;i<=m;++i) a[i]=qread();
for(int i=n;i>=1;--i) nxt[i]=last[f[i]],last[f[i]]=i; //处理出nxt和last数组。
for(int i=1;i<=m;++i) {
if(last[i]) { //如果这个电影已经播放过。
int zrj=nxt[last[i]];
if(zrj) modify(1,1,n,last[i],zrj-1,a[i]);
//如果这不是最后一次播放这个电影,那么可以影响到的最右端点是nxt[last[i]]-1,然后last[i]就是左端点,也是第一次看,所以在这个区间加上这个电影的价值。
else modify(1,1,n,last[i],n,a[i]); //如果是最后一次,那么它将一直影响到最后。
}
}
for(int i=1;i<=n;++i) {
ans=max(ans,tree[1].maxx); //每次更新一下最大值。
int zrj=nxt[i];
if(zrj) { //如果第二次播放。
modify(1,1,n,i,zrj-1,-a[f[i]]); //在这次和之后的一次的区间上价值减去这个电影的价值,因为相同电影看了价值为0。
if(nxt[zrj]) modify(1,1,n,zrj,nxt[zrj]-1,a[f[i]]); //第二次和第三次之间加上这个电影的价值(因为是以第二次为左端点,只看了一次)。
else modify(1,1,n,zrj,n,a[f[i]]); //不然就把第二次之后的加上这个价值。
}
else modify(1,1,n,i,n,-a[f[i]]); //没有第二次播放,就从当前时间开始一直到最后,减去这个价值。
}
printf("%lld\n",ans);
return 0;
}

洛谷P3582 [POI2015]KIN的更多相关文章

  1. BZOJ 4385 洛谷3594 POI2015 WIL-Wilcze doły

    [题解] 手残写错调了好久QAQ...... 洛谷的数据似乎比较水.. n个正整数!!这很重要 这道题是个类似two pointer的思想,外加一个单调队列维护当前区间内长度为d的子序列中元素之和的最 ...

  2. 洛谷 P3586 [POI2015]LOG

    P3586 [POI2015]LOG 题目描述 维护一个长度为n的序列,一开始都是0,支持以下两种操作:1.U k a 将序列中第k个数修改为a.2.Z c s 在这个序列上,每次选出c个正数,并将它 ...

  3. 洛谷P3588 - [POI2015]Pustynia

    Portal Description 给定一个长度为\(n(n\leq10^5)\)的正整数序列\(\{a_n\}\),每个数都在\([1,10^9]\)范围内,告诉你其中\(s\)个数,并给出\(m ...

  4. 洛谷 P3585 [POI2015]PIE

    P3585 [POI2015]PIE 题目描述 一张n*m的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色.你有一个a*b的印章,有些格子是凸起(会沾上墨水)的.你需要判断能否用这个印章印出纸上 ...

  5. 洛谷P3588 [POI2015]PUS

    题面 sol:说了是线段树优化建图的模板... 就是把一整个区间的点连到一个点上,然后用那个点来连需要连一整个区间的点就可以了,就把边的条数优化成n*log(n)了 #include <queu ...

  6. 洛谷P3586 [POI2015]LOG(贪心 权值线段树)

    题意 题目链接 Sol 显然整个序列的形态对询问没什么影响 设权值\(>=s\)的有\(k\)个. 我们可以让这些数每次都被选择 那么剩下的数,假设值为\(a_i\)次,则可以\(a_i\)次被 ...

  7. 洛谷P3588 [POI2015]PUS(线段树优化建图)

    题面 传送门 题解 先考虑暴力怎么做,我们把所有\(r-l+1-k\)中的点向\(x\)连有向边,表示\(x\)必须比它们大,那么如果这张图有环显然就无解了,否则的话我们跑一个多源最短路,每个点的\( ...

  8. 洛谷P3585 [POI2015]PIE

    传送门 题目大意:有个n*m的格子图,要求'x'点要被染成黑色 有个a*b的印章,'x'是可以染色的印章上的点. 要求用印章去染色格子 (1)印章不可以旋转. (2)不能把墨水印到纸外面. (3)纸上 ...

  9. BZOJ 3747 洛谷 3582 [POI2015]Kinoman

    [题解] 扫描线+线段树. 我们记第i部电影上次出现的位置是$pre[i]$,我们从$1$到$n$扫描,每次区间$(pre[i],i]$加上第i部电影的贡献$w[f[i]]$,区间$[pre[pre[ ...

随机推荐

  1. hdu-5861 Road(并查集)

    题目链接: Road Time Limit: 12000/6000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Pro ...

  2. APIO2017 游记

    参加了APIO的同学肯定知道我为什么只写标题不写内容. QAQ

  3. django models class 不识别问题解决方案

    目录 1. 事情起因 2. 排查经过 3. 总结 1. 事情起因 今天在写代码的时候,在django 的models目录中新增了一个pkg.py文件,里面定义了一个class, 在执行 makemig ...

  4. 深入理解javascript中的立即执行函数

    这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是用(function(){…})()包住业务代码,使用jquery时比较常见,需要的朋友可以 ...

  5. HDOJ1059(多重部分和问题)

    #include<cstdio> #include<cstring> using namespace std; +; ]; int dp[SIZE]; bool check() ...

  6. Python:生成器函数

    生成器函数:包含yield语句的函数: 生成器对象:生成器对象和迭代器对象行为相似,都支持可迭代接口:__next__(),若想执行生成器函数内部语句,则需要迭代协议’ A.生成器函数被调用时,并不会 ...

  7. JAVAWeb SSH框架 上传文件,如2007的EXCEL

    下面的代码是上传EXCEL的代码,其实,就是在上传文件到服务器,代码都差不多,只是接收的文件的类型改一下即可. 1.jsp 用的是struts2 标签 代码: <s:file name=&quo ...

  8. BAT小米奇虎美团迅雷携程等等各大企业校招,笔试面试题。

    类似在线测试的方式展示题目. 历年在线笔试试卷: 百度 http://www.nowcoder.com/paper/search?query=%E7%99%BE%E5%BA%A6  腾讯http:// ...

  9. 关于android中两种service的编写简单总结

    1.startservice (两种方法,继承service类或者继承intentservice 类) 继承service类,在onstartcommend重载方法中实现业务逻辑的处理,如果耗时过长最 ...

  10. ubuntu判断系统是32位还是64位

    1. 打开终端. 2. 输入命令  sudo uname -m 3. 如果输出为 x86_64, 则说明是64位操作系统:如果输出为 i686,说明是32位操作系统.