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;
}
辣鸡老年选手AFO在即