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
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。
样例解释:
观看第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 }
本文为博主原创文章,转载请注明出处。