1. 程式人生 > 實用技巧 >BZOJ #4282. 慎二的隨機數列

BZOJ #4282. 慎二的隨機數列

陳指導的考試題都沒做過來補一補部落格

這題剛開始想了一個naive的做法,先找出給定位置的LIS再把任填的加上去

但這樣顯然是GG的,後來想按每個給定位置為結尾DP,想要優化到\(O(n\log 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;
}