首页 > 代码库 > Bzoj3747 [POI1015] Kinoman

Bzoj3747 [POI1015] Kinoman

 

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

15
样例解释:
观看第2,3,4,5,6,7天内放映的电影,其中看且仅看过一次的电影的编号为2,3,4。

 

Bzoj权限题。只过了样例,尚未评测。

题面搬运自神犇hzwer博客。

 

 

线段树维护区间最值,枚举区间起点,不断把起点前面的电影贡献值删去,再把当前电影“从当前直到它下次出现之前”的区间都新加上当前电影的贡献值,不断更新最大答案。

刚开始按区间加法写的,所以变量用了sum,写到一半发现只搞区间最大值就好,然而懒得改变量名了……

 

 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<cmath> 6 #define ls l,mid,rt<<1 7 #define rs mid+1,r,rt<<1|1 8 #define LL long long 9 using namespace std;10 const int mxn=1000010;11 int n,m;12 int f[mxn],w[mxn];13 int next[mxn],last[mxn];14 int cnt[mxn];15 struct node{16     LL sum;//变量名是sum,实际是存区间最大值 17     LL tag;18 }t[mxn<<2];19 void Build(int l,int r,int rt){//init //实际并没有用到 20     if(l==r){21         t[rt].sum=t[rt].tag=0;22         return;23     }24     int mid=(l+r)>>1;25     Build(ls);Build(rs);26     return;27 }28 void pushdown(int l,int r,int rt){29     if(l==r)return;30     if(t[rt].tag){ 31         int mid=(l+r)>>1;32         t[rt<<1].tag+=t[rt].tag;33         t[rt<<1|1].tag+=t[rt].tag;34         t[rt<<1].sum+=t[rt].tag;35         t[rt<<1|1].sum+=t[rt].tag;36         t[rt].tag=0;37     }38 }39 void add(int L,int R,int v,int l,int r,int rt){40     if(t[rt].tag)pushdown(l,r,rt);41     if(L<=l && r<=R){42         t[rt].tag+=v;43         t[rt].sum+=v;44         return;45     }46     int mid=(l+r)>>1;47     if(L<=mid)add(L,R,v,ls);48     if(R>mid)add(L,R,v,rs);49     t[rt].sum=max(t[rt<<1].sum,t[rt<<1|1].sum);50     return;51 }52 void read(){53     scanf("%d%d",&n,&m);54     int i,j;55     for(i=1;i<=n;i++)scanf("%d",&f[i]);56     for(i=1;i<=m;i++)scanf("%d",&w[i]);57     return;58 }59 int main(){60     read();61     int i,j;62     for(i=n;i;i--){63         next[i]=last[f[i]];64         last[f[i]]=i;65     }66     for(i=1;i<=m;i++){67         if(last[i]){68             if(!next[last[i]])add(last[i],n,w[i],1,n,1); 69             else add(last[i],next[last[i]]-1,w[i],1,n,1);70         }71     }72     LL ans=0;73     for(i=1;i<=n;i++){74         ans=max(ans,t[1].sum);75         int tmp=next[i];76         if(tmp){77             add(i,tmp-1,-w[f[i]],1,n,1);78             if(next[tmp])add(tmp,next[tmp]-1,w[f[i]],1,n,1); 79             else add(tmp,n,w[f[i]],1,n,1);//如果之后没有相同电影了,从next[i]到n的区间都加值 80         }81         else add(i,n,-w[f[i]],1,n,1);//删除上一个区间的值 82     }83     printf("%lld",ans);84     return 0;85 }

 

Bzoj3747 [POI1015] Kinoman