选举 - 线段树 -单调队列 - dp

题目大意:
给定序列a,满足 a i { 1 , 0 , 1 } a_i\in\{-1,0,1\} ;定义 w ( l , r ) = s g n ( i = l r a i ) w(l,r)=sgn(\sum_{i=l}^r a_i) ,其中sgn为符号函数。将a划分成若干长度在[l,r]之间的段,使得每一段的权值之和最大。 n 1 0 6 n\le10^6
题解:
写了个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)
于是你只关心 S i S_i S j S_j 的大小关系,对S建立线段树,维护那些S相等的j关于f的单调队列即可,这样就是O(nlgn)。
线性做法是,考虑f和S的值域都是O(n)级别的,且 w ( l , r ) 1 |w(l,r)|\le1 ,因此在计算f的时候,只有最大的 f j f_j f j 1 f_j-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]);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82998910
今日推荐