• BZOJ3747:[POI2015]Kinoman——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=3747

    https://www.luogu.org/problemnew/show/P3582

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

    参考洛谷题解。

    做法很神,为了符合人类直观思路,我们枚举左端点,然后O(log)找到答案最大的右端点。

    然后就各种维护,维护一下前缀和,存在每个节点里。

    当左端点移动时其原先对应的端点对后续的影响就消除了,此时需要重新修改各种值。

    语言不是很好说,可以看我的代码,也可以看洛谷的全注释版。

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1000005;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int n,m,f[N],w[N],nxt[N],head[N];
    ll tr[N*4],lz[N*4];
    inline void add(int u,int cnt){
        nxt[cnt]=head[u];head[u]=cnt;
    }
    inline void push(int a){
        if(!lz[a])return;
        lz[a<<1]+=lz[a];lz[a<<1|1]+=lz[a];
        tr[a<<1]+=lz[a];tr[a<<1|1]+=lz[a];
        lz[a]=0;
    }
    void mdy(int a,int l,int r,int l1,int r1,int w){
        if(r<l1||r1<l)return;
        if(l1<=l&&r<=r1){
        tr[a]+=w;lz[a]+=w;
        return;
        }
        push(a);
        int mid=(l+r)>>1;
        mdy(a<<1,l,mid,l1,r1,w);mdy(a<<1|1,mid+1,r,l1,r1,w);
        tr[a]=max(tr[a<<1],tr[a<<1|1]);
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++)f[i]=read();
        for(int i=1;i<=m;i++)w[i]=read();
        for(int i=n;i>=1;i--)add(f[i],i);
        for(int i=1;i<=m;i++){
        if(head[i]){
            if(!nxt[head[i]])mdy(1,1,n,head[i],n,w[i]);
            else mdy(1,1,n,head[i],nxt[head[i]]-1,w[i]);
        }
        }
        ll ans=0;
        for(int i=1;i<=n;i++){
        ans=max(ans,tr[1]);
        int t=nxt[i];
        if(t){
            mdy(1,1,n,i,t-1,-w[f[i]]);
            if(nxt[t])mdy(1,1,n,t,nxt[t]-1,w[f[i]]);
            else mdy(1,1,n,t,n,w[f[i]]);
        }else mdy(1,1,n,i,n,-w[f[i]]);
        }
        printf("%lld
    ",ans);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    字符串转换日期,日期转换字符串
    List中的Map
    一维数组
    流程控制的基本语法和应用
    《代码阅读方法与实践》读书笔记1
    专业实训题目需求分析
    2015年秋季个人阅读计划
    《人件集 人性化的软件开发》阅读笔记03
    《人件集 人性化的软件开发》阅读笔记02
    《人件集 人性化的软件开发》阅读笔记01
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9070506.html
Copyright © 2020-2023  润新知