BZOJ #4282. 慎二的随机数列

陈指导的考试题都没做过来补一补博客

这题刚开始想了一个naive的做法,先找出给定位置的LIS再把任填的加上去

但这样显然是GG的,后来想按每个给定位置为结尾DP,想要优化到(O(nlog n))就要用平衡树优化DP

但后来再仔细一想,发现真正需要关注的不是给定的位置而是任选的位置,因为如果为了一个给定位置而放弃一些任选位置显然是会更优的

因此我们先强制所有不给定的位置都要选,现在就是要最大化能选的给定位置的个数

考虑此时对于两个给定的位置(i,j),当(a_i+x<a_j)这两个数才能同时选,其中(x)表示([i,j])中不给定的位置个数

(x)用前缀和(pfx_j-pfx_i)代掉,现在的限制变成了(a_i-pfx_i<a_j-pfx_j),因此直接对({a_i-pfx_i})做LIS即可

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,a[N],x,rst[N],pfx[N],m,ans; char ch;
class Tree_Array
{
	private:
		int bit[N];
	public:
		#define lowbit(x) (x&-x)
		inline int get(RI x,int ret=0)
		{
			for (;x;x-=lowbit(x)) ret=max(ret,bit[x]); return ret;
		}
		inline void add(RI x,CI y)
		{
			for (;x<=m;x+=lowbit(x)) bit[x]=max(bit[x],y);
		}
		#undef lowbit
}BIT;
int main()
{
	//freopen("cauchy.in","r",stdin); freopen("cauchy.out","w",stdout);
	RI i; for (scanf("%d",&n),a[0]=-2e9,i=1;i<=n;++i)
	{
		while (ch=getchar(),ch!='N'&&ch!='K'); scanf("%d",&x);
		if (ch=='K') a[i]=x; else pfx[i]=1;
	}
	for (i=1;i<=n;++i) if (pfx[i]+=pfx[i-1],a[i]) rst[++m]=a[i]=a[i]-pfx[i];
	for (sort(rst+1,rst+m+1),m=unique(rst+1,rst+m+1)-rst-1,i=1;i<=n;++i)
	if (a[i]) a[i]=lower_bound(rst+1,rst+m+1,a[i])-rst,
	ans=max(ans,x=BIT.get(a[i]-1)+1),BIT.add(a[i],x);
	return printf("%d",ans+pfx[n]),0;
}
原文地址:https://www.cnblogs.com/cjjsb/p/13776606.html