题目大意:
给定序列a,满足
a
i
∈
{
−
1
,
0
,
1
}
a_i\in\{-1,0,1\}
ai∈{−1,0,1};定义
w
(
l
,
r
)
=
s
g
n
(
∑
i
=
l
r
a
i
)
w(l,r)=sgn(\sum_{i=l}^r a_i)
w(l,r)=sgn(∑i=lrai),其中sgn为符号函数。将a划分成若干长度在[l,r]之间的段,使得每一段的权值之和最大。
n
≤
1
0
6
n\le10^6
n≤106
题解:
写了个nlgn得了90,真……
nlgn做法是,考虑:
f
i
=
max
j
∈
[
i
−
r
,
i
−
l
]
d
p
j
+
s
g
n
(
S
i
−
S
j
)
f_i=\max_{j\in[i-r,i-l]}dp_j+sgn(S_i-S_j)
fi=j∈[i−r,i−l]maxdpj+sgn(Si−Sj)
于是你只关心
S
i
S_i
Si和
S
j
S_j
Sj的大小关系,对S建立线段树,维护那些S相等的j关于f的单调队列即可,这样就是O(nlgn)。
线性做法是,考虑f和S的值域都是O(n)级别的,且
∣
w
(
l
,
r
)
∣
≤
1
|w(l,r)|\le1
∣w(l,r)∣≤1,因此在计算f的时候,只有最大的
f
j
f_j
fj和
f
j
−
1
f_j-1
fj−1才是有用的,那么对于这两个数值,显然前缀和越小越好,因此维护O(n)个单调队列,每个单调队列是f值确定时关于S的单调队列,最后全局搞一个关于f的单调队列来维护这个区间最大即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define N 2000010
#define inf -100000000
using namespace std;typedef pair<int,int> pii;typedef set<int>::iterator sit;
inline int inn()
{
int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-');if(ch^'-') x=ch^'0';else s=-1;
while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return s*x;
}
int bas,dp[N],s[N],a[N];inline int sgn(int x) { return (x<0)?-1:(x>0); }
struct Qmax{
int fp,rp;vector<pii> q; Qmax() { fp=0,rp=-1; }
inline void push(pii t) { q.resize((int)q.size()+1);while(fp<=rp&&t.fir>=q[rp].fir) rp--;q[++rp]=t; }
inline int front() { return fp<=rp?q[fp].fir:inf; } inline void pop(int t) { fp+=(fp<=rp&&q[fp].sec==t); }
}q;
struct Qmin{
Qmax q;inline void push(pii t) { q.push(mp(-t.fir,t.sec)); }
inline int front() { return -q.front(); } inline void pop(int t) { q.pop(t); }
}f[N];
inline int ins(int x) { if(x<0||dp[x]+bas<=0) return 0;return q.push(mp(dp[x],x)),f[dp[x]+bas].push(mp(s[x],x)),0; }
inline int del(int x) { if(x<0||dp[x]+bas<=0) return 0;return q.pop(x),f[dp[x]+bas].pop(x),0; }
int main()
{
int n=inn(),l=inn(),r=inn();bas=n+1;rep(i,1,n) a[i]=inn(),s[i]=s[i-1]+a[i];
for(int i=1;i<=n;i++)
{
dp[i]=inf,del(i-r-1),ins(i-l);int v=q.front(),s1=-inf,s2=-inf;
if(v+bas>0) s1=f[v+bas].front();if(s1<-inf) dp[i]=max(dp[i],v+sgn(s[i]-s1));
if(v+bas-1>0) s2=f[v+bas-1].front();if(s2<-inf) dp[i]=max(dp[i],v-1+sgn(s[i]-s2));
}
if(dp[n]+bas>0) printf("%d\n",dp[n]);else printf("Impossible\n");return 0;
}
90pts code:
#include<bits/stdc++.h>
#define gc getchar()
#define inf -10000000
#define N 2000010
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-');
if(ch^'-') x=ch^'0';else s=-1;
while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');
return s*x;
}
vector<int> v[N];int fp[N],rp[N],pfs[N],s[N],a[N],dp[N],cnt[N],bas;
inline int S(int l,int r) { return (r>=0?pfs[r]:0)-(l-1>=0?pfs[l-1]:0); }
inline int ins(vector<int> &v,int &fp,int &rp,int p) { while(fp<=rp&&dp[p]>=dp[v[rp]]) rp--;return v[++rp]=p,dp[v[fp]]; }
inline int del(vector<int> &v,int &fp,int &rp,int p) { if(fp<=rp&&v[fp]==p) fp++;return fp<=rp?dp[v[fp]]:inf; }
struct segment{ int l,r,v;segment *ch[2]; }*rt;
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r,rt->v=inf;
if(l==r) return fp[l]=0,rp[r]=-1;int mid=(l+r)>>1;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
inline int push_up(segment* &rt) { return rt->v=max(rt->ch[0]->v,rt->ch[1]->v); }
int ins(segment* &rt,int p,int x)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(l==r) return rt->v=ins(v[p],fp[p],rp[p],x);
return ins(rt->ch[p>mid],p,x),push_up(rt);
}
int del(segment* &rt,int p,int x)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(l==r) return rt->v=del(v[p],fp[p],rp[p],x);
return del(rt->ch[p>mid],p,x),push_up(rt);
}
int query(segment* &rt,int s,int t)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return rt->v;int ans=inf;
if(s<=mid) ans=max(ans,query(rt->ch[0],s,t));
if(mid<t) ans=max(ans,query(rt->ch[1],s,t));
return ans;
}
inline int ins(int p) { if(p<0||!pfs[p]) return 0;return ins(rt,s[p]+bas,p); }
inline int del(int p) { if(p<0||!pfs[p]) return 0;return del(rt,s[p]+bas,p); }
inline int query(int l,int r) { return l<=r?query(rt,l+bas,r+bas):inf; }
int main()
{
int n=inn(),l=inn(),r=inn();pfs[0]=1;
for(int i=1;i<=n;i++) pfs[i]=pfs[i-1]+(S(i-r,i-l)>0);
for(int i=n;i>=1;i--) pfs[i]-=pfs[i-1];
if(!pfs[n]) return !printf("Impossible\n");
rep(i,1,n) a[i]=inn(),s[i]=s[i-1]+a[i];
bas=1;rep(i,1,n) bas=max(bas,-s[i]+1);
build(rt,1,n+bas);rep(i,1,n) cnt[s[i]+bas]++;cnt[bas]++;
rep(i,1,n+bas) if(cnt[i]) v[i].resize(cnt[i]);
for(int i=1;i<=n;i++)
{
dp[i]=inf,del(i-r-1),ins(i-l);
dp[i]=max(dp[i],query(-bas+1,s[i]-1)+1);
dp[i]=max(dp[i],query(s[i],s[i]));
dp[i]=max(dp[i],query(s[i]+1,n)-1);
}
return !printf("%d\n",dp[n]);
}