zoukankan      html  css  js  c++  java
  • 3747 [POI2015]Kinoman

    3747: [POI2015]Kinoman

    Time Limit: 30 Sec  Memory Limit: 128 MB

    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。
     
    这是Gromah学长给我的线段树操作第二道练习题。
    思路:
    ……一片混乱
    我开始先处理出a[i]代表看从1到i的电影的好看值,Ne[i]代表f[i]出现的下一个位置。
    然后将第1天的电影去掉之后,影响是第2天看到第i天(i取值从2到Ne[1]-1)都会好看值减去w[f[1]](即a[i]-=w[f[1]]),从第2天看到第i天(Ne[i]到Ne[Ne[i]]-1)都会好看值加上w[f[1]]。
    那么思路就出来了,只要从第1天处理到第n-1天,每次把当天删去,然后区间加法(线段树维护),对于每次处理后,都要查询最大值(另一个线段树维护)。
    24 Sec过了。
     
    (忽然想起UOJ上有人贴的一张图,刷一道时限为60Sec的题。这人竟然没被封号也是奇迹!)
     
     
    不说闲话,贴代码:
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 1050000
    int n,m,Ne[N],La[N],w[N],f[N];
    long long maxx=0,Ma[2*N],Zs[2*N];
    bool b[N];
    long long Max(long long x,long long y)
     {
        if (x>y) return x;else return y;
     }
    void Plin(int x,int y,int z,long long v,int t)
     {
        int i=(x+y)/2;
        if (x==y)
         {
            Zs[z]=v;
            return;
         }
        if (t>i)
          Plin(i+1,y,z*2+1,v,t);else
          Plin(x,i,z*2,v,t);
        Zs[z]=Max(v,Zs[z]);
        return;
     }
    void Insert(int x,int y,int z,int s,int t,int v)
     {
        int i=(z+s)/2;
        if (z==s)
         {
            Zs[t]+=v;
            return;
         }
        if (x==z&&y==s)
         {
            Ma[t]+=v;
            Zs[t]+=v;
            return;
         }
        if (x<=i)
          Insert(x,min(i,y),z,i,t*2,v);
        if (y>i)
          Insert(max(i+1,x),y,i+1,s,t*2+1,v);
        Zs[t]=Max(Zs[t*2],Zs[t*2+1])+Ma[t];
        return;
     }
    void Did(int x,int y,int z,int s,int t,int v)
     {
        if (x<=y)
          Insert(x,y,z,s,t,v);
        return;
     }
    int main()
     {
        int i,j,k,l,q;
        long long e;
        memset(Ma,0,sizeof(Ma));memset(La,0,sizeof(La));
        memset(b,0,sizeof(b));memset(w,0,sizeof(w));
        memset(f,0,sizeof(f));memset(Ne,0,sizeof(Ne));
        memset(Zs,0,sizeof(Zs));
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;i++)
          scanf("%d",&f[i]);
        for (i=1;i<=m;i++)
          scanf("%d",&w[i]);
        e=0;
        for (i=1;i<=n;i++)
         {
            if (La[f[i]]==0)
              e+=w[f[i]];else
             {
                Ne[La[f[i]]]=i;
                if (!b[f[i]])
                 {
                    e-=w[f[i]];
                    b[f[i]]=true;
                 }
             }
            Plin(1,n,1,e,i);
            La[f[i]]=i;
         }
        maxx=Zs[1];
        for (i=1;i<n;i++) 
         {
            if (Ne[i]==0)
              Did(i+1,n,1,n,1,-w[f[i]]);else
              {
                 Did(i+1,Ne[i]-1,1,n,1,-w[f[i]]);
                 if (Ne[Ne[i]]==0)
                   Did(Ne[i],n,1,n,1,w[f[i]]);else
                   Did(Ne[i],Ne[Ne[i]]-1,1,n,1,w[f[i]]);
              }
            maxx=Max(maxx,Zs[1]);
         }
        printf("%lld
    ",maxx);
        return 0;
     }
     
     
     
     
  • 相关阅读:
    c如何弹出保存路径/保存文件对话框
    c++ 读写txt方法
    windows获取环境变量
    Block UI 获取treelist column值
    MFC中如何弹出选择文件/文件夹对话框(C++)
    What can change the CID of a NX license server?
    spring之AOP
    spring注解开发
    spring配置Bean
    spring之IOC和DI实现
  • 原文地址:https://www.cnblogs.com/HJWJBSR/p/4149913.html
Copyright © 2011-2022 走看看