【POI2015】KIN/Kinoman
題目鏈接
傳送門-洛谷
傳送門-bzoj
思路
考慮枚舉右端點。首先考慮應用前綴和,對于一個r,找一個最小的sum[l],把需要去掉的部分也放到sum[l]里。但這種做法是錯的….對于一個i,把他上一次出現的位置記做pre[i],每次把1到pre[i]之間所有區間的前綴和都加上一個w[i],但是不論如何區間中第一次出現的數是會被計算的,所以這樣不可以。
考慮另一種表示方式,對于每個遇到的 i ,把1到 i 這段都加上w[i],這樣的話sum[j]就表示的是 j 到 i 的連續區間和。然后考慮如何使得每個pre[i]之前的位置第i種電影的貢獻是0。重新考察剛剛那種做法為什么不對,不把那個多出來的次數當成第一個數,而是理解為每次區間中有一個重復的,我們會在求和的時候加一次,減去的時候減一次,相當于沒有減。于是這次我們考慮不讓他加上,只減去。于是每次遇到一個i,是把pre[i]+1到i加上w[i],把pre[pre[i]]+1到pre[i]減去,這樣使得任意pre[i]之前的都不會計算 i 的貢獻。
回顧我們的表示方法,他的好處是使得我們可以控制加減的范圍,而當使用前綴和的時候,我們無法控制每個值加在了哪里,只能進行減,于是無法操作。
如果還沒有理解的可以看看代碼
UPD:(套路部分)
對于一類允許離線,且對區間中數字出現個數有要求的題目,可以考慮按順序將點加入,然后適當對pre[u], pre[pre[u]]等進行修改操作
代碼
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #include <math.h> #include <set> #define MAXN 1000050 #define INF (1<<28) #define LLINF (1LL<<40) #define LL long long using namespace std; int n, m, f[MAXN], w[MAXN], pre[MAXN], app[MAXN]; struct node{LL maxn, lazy; }t[MAXN<<2]; void push_down(int u){if(t[u].lazy){t[u<<1].lazy += t[u].lazy, t[u<<1].maxn += t[u].lazy;t[u<<1|1].lazy += t[u].lazy, t[u<<1|1].maxn += t[u].lazy;t[u].lazy = 0;} } void add(int u, int l, int r, int tl, int tr, int x){if(tl > tr) return;if(tl <= l && r <= tr){t[u].maxn += x, t[u].lazy += x;return;}push_down(u);int mid = (l+r)>>1;if(tl <= mid) add(u<<1, l, mid, tl, tr, x);if(mid < tr) add(u<<1|1, mid+1, r, tl, tr, x);t[u].maxn = max(t[u<<1].maxn, t[u<<1|1].maxn); } LL query(int u, int l, int r, int tl, int tr){if(tl <= l && r <= tr){return t[u].maxn;}push_down(u);int mid = (l+r)>>1; LL ret = 0;if(tl <= mid) ret = max(ret, query(u<<1, l, mid, tl, tr));if(mid < tr) ret = max(ret, query(u<<1|1, mid+1, r, tl, tr));return ret; } /* 共有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],…,fn。 第三行包含m個整數w[1],w[2],…,wm。輸出格式: 輸出觀看且僅觀看過一次的電影的好看值的總和的最大值。*/ int main() {scanf("%d%d", &n, &m);for(int i = 1; i <= n; i++) {scanf("%d", &f[i]);pre[i] = app[f[i]];app[f[i]] = i;}LL ans = 0;for(int i = 1; i <= m; i++) scanf("%d", &w[i]);for(int i = 1; i <= n; i++) {add(1, 1, n, pre[i]+1, i, w[f[i]]);add(1, 1, n, pre[pre[i]]+1, pre[i], -w[f[i]]);/*The following 2 lines are wrong!add(1, 1, n, 1, i, w[f[i]]);add(1, 1, n, 1, pre[i], -w[f[i]]);*/ans = max(ans, query(1, 1, n, 1, n));}printf("%lld", ans);return 0; }轉載于:https://www.cnblogs.com/hychyc/p/9727469.html
總結
以上是生活随笔為你收集整理的【POI2015】KIN/Kinoman的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全网最详细的大数据集群环境下如何正确安装
- 下一篇: sqlserver 性能问题