zoukankan      html  css  js  c++  java
  • [BZOJ3747] Kinoman

    问题描述

    共有m部电影,编号为1~m,第i部电影的好看值为w[i]。

    在n天之中(从1~n编号)每天会放映一部电影,第i天放映的是第f[i]部。

    你可以选择l,r(1<=l<=r<=n),并观看第l,l+1,…,r天内所有的电影。如果同一部电影你观看多于一次,你会感到无聊,于是无法获得这部电影的好看值。所以你希望最大化观看且仅观看过一次的电影的好看值的总和。

    输入格式

    第一行两个整数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)。

    输出格式

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

    样例输入

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

    样例输出

    15

    样例解释

    15
    样例解释:

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

    链接

    BZOJ

    解析

    考虑如何解决重复电影没有贡献的问题。记第(i)的电影前面一次出现的时候为(L[i]),后面一次出现的时候为(R[i]),那么这个电影能够计贡献的区间为([i,R[i]-1])。所以,我们把所有电影按照(L[i])排序,然后枚举选择区间的左端点,用线段树维护答案。每次将左端点以前的贡献在线段树中减掉,同时在满足条件的区间中加入(L[i])小于当前左端点的天的贡献。维护最大值即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define N 1000002
    using namespace std;
    struct SegmentTree{
        long long dat,add;
    }t[N*4];
    struct day{
        int l,r,w,p;
    }a[N],b[N];
    int n,m,i,j,k,pos[N],f[N],w[N];
    long long ans;
    int read()
    {
        char c=getchar();
        int w=0;
        while(c<'0'||c>'9') c=getchar();
        while(c<='9'&&c>='0'){
            w=w*10+c-'0';
            c=getchar();
        }
        return w;
    }
    int my_comp(const day &x,const day &y)
    {
        if(x.l==y.l) return x.p<y.p;
        return x.l<y.l;
    }
    void spread(int p)
    {
        if(t[p].add){
            t[p*2].add+=t[p].add;
            t[p*2+1].add+=t[p].add;
            t[p*2].dat+=t[p].add;
            t[p*2+1].dat+=t[p].add;
            t[p].add=0;
        }
    }
    void change(int p,int l,int r,int ql,int qr,int x)
    {
        if(ql<=l&&r<=qr){
            t[p].dat+=x;
            t[p].add+=x;
            return;
        }
        int mid=(l+r)/2;
        spread(p);
        if(ql<=mid) change(p*2,l,mid,ql,qr,x);
        if(qr>mid) change(p*2+1,mid+1,r,ql,qr,x);
        t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
    }
    signed main()
    {
        n=read();m=read();
        for(i=1;i<=n;i++) f[i]=read();
        for(i=1;i<=m;i++) w[i]=read();
        for(i=1;i<=n;i++) a[i].w=w[f[i]],a[i].p=i;
        for(i=1;i<=n;i++){
            a[i].l=pos[f[i]];
            pos[f[i]]=i;
        }
        memset(pos,0,sizeof(pos));
        for(i=n;i>=1;i--){
            a[i].r=pos[f[i]]==0?n+1:pos[f[i]];
            pos[f[i]]=i;
        }
        for(i=1;i<=n;i++) b[i]=a[i];
        sort(a+1,a+n+1,my_comp);
        j=k=1;
        for(i=1;i<=n;i++){
            if(i>1) change(1,1,n,b[i-1].p,b[i-1].r-1,-b[i-1].w);
            while(a[j].l<i&&j<=n) change(1,1,n,a[j].p,a[j].r-1,a[j].w),j++;
            ans=max(ans,t[1].dat);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Leetcode NO.110 Balanced Binary Tree 平衡二叉树
    Leetcode NO.226 Invert Binary Tree 翻转二叉树
    Leetcode NO.215 Kth Largest Element In An Array 数组中的第K个最大元素
    根据特征的浏览器判断
    Cygwin在打开在当前目录
    【转帖】科学对待 健康养猫 打造快乐孕妇
    解决chrome浏览器安装扩展、应用程序一直处在“检查中”的问题
    对【SQL SERVER 分布式事务解决方案】的心得补充
    关于“点击这里继续访问您选择的百度XXX”
    VBA一例:如何保持文本框焦点
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12231520.html
Copyright © 2011-2022 走看看