NKOJ-3772 看電影

P3772看電影
時間限制 : - MS 空間限制 : 165536 KB
評測說明 : 1000ms
問題描述

共有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

提示

樣例解釋:

觀看第2,3,4,5,6,7天內放映的電影,其中看且僅看過一次的電影的編號爲2,3,4。

來源 poi2015

由於不想寫代碼 所以我就把題解先寫了

題解

分析解法

首先 這道題目的解法非常暴力
就是把每一個子區間的和都給求出來

比如對於區間[1,3]
它的結果就在[1,1] [2,2] [3,3] [1,2] [2,3] [1,3]的和中取最大值

所以這道題目的解法其實有點像差分數組

差分數組的模式是
    規定求和時加一個值的邊界[l,r]
    當你的求和的終點在[l,r)就加上這個值
    反之則不加

而差分數組的處理模式是
    add[l]=x
    add[r]=-x
這個樣子我們就可以達到快速求[l,r]的和的目的

反觀這道題目

討論對於電影相同的區間[l,r] (即l,r的電影相同)
僅當求和區間屬於(l,r]時才加入
同時包含l和r時就不加入

那麼我們來思考一下能否用類似於差分數組的方法來解決這道題目

差分數組在這道題目當中的缺陷在於

假設我們對[1,5]都加上x(add[1]=x,add[6]=-x)
那麼只有當我們的求和區間包含了1號點的時候才能夠加上x

問題出來了
假設 第3,6天觀看同一部電影 且好感度爲y

那麼對於當前討論的點爲3時
add[1]=y add[4]=-y
當我們求的是[2,3] y就不能被計算進去

所以我們就需要一個更有效的求和方案:線段樹
但是此時我們的求和也不再盲目了
我們已經知道求和需要用到類似於差分數組的方式才能處理題目的要求

所以再次討論[1,2]

我們可以直接選擇在[1,2]的區間上+y
這樣在討論[1,2]時就能夠正確計算+y

而討論[1,6]時

由於先前已經討論過了[1,2]
所以之後的討論我們所涉及到的都是求和區間[l,r]的右端點r=6的情況
此時若是再以[1,2]中的點爲起點 就不能加上+y
所以我們的操作是
    [1,2]在原先+y的基礎上-y
    [3,6]全體+y
    這樣就能夠在求和區間起點爲[3,6]時正確地+y

通過上述操作 我們就得到了一種電影的求和方式
而其它的電影也可以通過相同的方式進行點的修改

理解重點

如此一來 在每次操作之後 每個點的值對應的都是以這個點爲起點此次操作的點看電影好感度

因此 我們在每次操作之後都要更新一次答案

附上對拍代碼

#include <iostream>
#include <cstdio>
#define mid (l+r>>1)
using namespace std;

int n,m,happy[5001234],wait[5001234];
int ll,rr,x;
int film,f[1001234],nxt[1001234],las[1001234],pos[1001234],co[1001234];

inline int input()
{
    char c=getchar();int o;
    while(c>57||c<48)c=getchar();
    for(o=0;c>47&&c<58;c=getchar())o=(o<<1)+(o<<3)+c-48;
    return o;
}

void PD(int l,int r,int ori)
{
    if(l!=r)
    {
        wait[ori<<1]+=wait[ori];
        wait[ori<<1|1]+=wait[ori];
        happy[ori<<1]+=wait[ori];
        happy[ori<<1|1]+=wait[ori];
    }
    wait[ori]=0;
}

void add(int l,int r,int ori)
{
    if(ll<=l&&r<=rr)
    {
        happy[ori]+=x;
        wait[ori]+=x;
        return;
    }
    if(wait[ori])PD(l,r,ori);
    if(ll<=mid&&l<=rr)add(l,mid,ori<<1);
    if(mid<rr&&ll<=r)add(mid+1,r,ori<<1|1);
    happy[ori]=max(happy[ori<<1],happy[ori<<1|1]);
}

int main()
{
    int res=0;
    n=input();m=input();
    for(int i=1;i<=n;i++)
    {
        f[i]=film=input();
        las[i]=pos[f[i]];
        pos[f[i]]=i;
    }
    for(int i=1;i<=m;i++)co[i]=input();//co爲電影好感度
    for(int i=1;i<=n;i++)
    {
        ll=las[las[i]];rr=las[i];x=-co[f[i]];
        add(1,n,1);
        ll=las[i]+1;rr=i;x=-x;
        add(1,n,1);
        res=max(res,happy[1]);
    }
    printf("%d",res);
}
發佈了79 篇原創文章 · 獲贊 15 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章