D
e
s
c
r
i
p
t
i
o
n
\mathcal{Description}
Description
S
o
l
u
t
i
o
n
\mathcal{Solution}
Solution
设
F
[
i
]
表
示
前
i
个
选
民
的
最
优
答
案
,
得
到
F
[
i
]
=
m
a
x
{
F
[
j
]
+
1
(
s
u
m
i
>
s
u
m
j
)
F
[
j
]
(
s
u
m
i
=
s
u
m
j
)
F
[
j
]
−
1
(
s
u
m
i
<
s
u
m
j
)
设F[i]表示前i个选民的最优答案,得到\\ F[i]=max\begin{cases} F[j]+1\ \ \ \ \ \ \ \ \ (sum_i>sum_j) \\ F[j] \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (sum_i=sum_j)\\ F[j]-1\ \ \ \ \ \ \ \ \ (sum_i<sum_j) \end{cases}
设F[i]表示前i个选民的最优答案,得到F[i]=max⎩⎪⎨⎪⎧F[j]+1 (sumi>sumj)F[j] (sumi=sumj)F[j]−1 (sumi<sumj)
复杂度
O
(
N
2
)
O(N^2)
O(N2).
优
化
部
分
:
优化部分:
优化部分:
以
s
u
m
n
{sum_n}
sumn 为下标建立 权值线段树,
线段树的每个叶子节点保存
满
足
s
u
m
i
=
叶
子
下
标
\color{blue}{满足sum_i=叶子下标}
满足sumi=叶子下标 的每个
i
i
i 位置上的
最
大
F
[
]
值
\color{red}{最大F[]值}
最大F[]值.
则可以直接查询比当前 s u m i sum_i sumi 值 小的,大的,相等的 最大的 F [ j ] F[j] F[j], O ( l o g n ) O(logn) O(logn) 实现单次转移.
每次 i + + i++ i++ 前, i − L + 1 i-L+1 i−L+1 可以被合法转移, i − R + 1 i-R+1 i−R+1 不能被合法转移, 于是在线段树中删除掉其对应的 d p dp dp 值.
bug
C
o
d
e
\mathcal{Code}
Code
#include<bits/stdc++.h>
#define reg register
typedef std::pair<int, int> pr;
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ flag = -1, c = getchar(); break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int maxn = 1e6 + 6;
const int inf = 0x3f3f3f3f;
int N;
int L;
int R;
int Lim;
int A[maxn];
int F[maxn];
int sum[maxn];
struct Node{
std::priority_queue <pr> que;
int l, r, max_v;
} T[maxn*4];
void Build(int k, int l, int r){ //
T[k].l = l, T[k].r = r;
if(l == r){ T[k].max_v = -inf; return ; }
int mid = l+r >> 1;
Build(k<<1, l, mid), Build(k<<1|1, mid+1, r);
T[k].max_v = -inf;
}
void Modify(int k, int id){ //
int l = T[k].l, r = T[k].r;
if(l == r){
T[k].que.push(pr(F[id], id));
T[k].max_v = T[k].que.top().first;
return ;
}
int mid = l+r >> 1;
if(sum[id] <= mid) Modify(k<<1, id);
else Modify(k<<1|1, id);
T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v);
}
void Del(int k, int id){ //
int l = T[k].l, r = T[k].r;
if(l == r){
while(!T[k].que.empty() && T[k].que.top().second < Lim) T[k].que.pop();
if(T[k].que.empty()) T[k].max_v = -inf;
else T[k].max_v = T[k].que.top().first;
return ;
}
int mid = l+r >> 1;
if(sum[id] <= mid) Del(k<<1, id);
else Del(k<<1|1, id);
T[k].max_v = std::max(T[k<<1].max_v, T[k<<1|1].max_v);
}
int Query(int k, int Ql, int Qr){ //
int l = T[k].l, r = T[k].r;
if(Ql <= l && r <= Qr) return T[k].max_v;
int mid = l+r >> 1;
if(mid+1 <= Ql) return Query(k<<1|1, Ql, Qr);
else if(mid >= Qr) return Query(k<<1, Ql, Qr);
return std::max(Query(k<<1, Ql, Qr), Query(k<<1|1, Ql, Qr));
}
int main(){
freopen("election.in", "r", stdin);
freopen("election.out", "w", stdout);
N = read(), L = read(), R = read();
for(reg int i = 1; i <= N; i ++) A[i] = read(), sum[i] = sum[i-1] + A[i];
for(reg int i = 0; i <= N; i ++) sum[i] += N;
memset(F, -0x3f, sizeof F); F[0] = 0;
Build(1, 0, N<<1); Modify(1, 0);
for(reg int i = L; i <= N; i ++){
Lim = std::max(i-R, 0);
F[i] = std::max(F[i], Query(1, 0, std::max(0, sum[i]-1)) + 1);
F[i] = std::max(F[i], Query(1, sum[i], sum[i]));
F[i] = std::max(F[i], Query(1, std::min(sum[i]+1, N<<1), N<<1) - 1);
if(i-R >= 1) Del(1, i-R);
if(i-L >= 0) Modify(1, i-L);
}
printf("%d\n", F[N]);
return 0;
}
/*
Bug List:
1. Build -> push_up
2. For(int i = 1; i <= N; i ++) <<-- For(int i = L; i <= N; i ++)
*/