CFGYM101915 I A Movie in Byteland (二维LIS+树状数组优化dp)
Mean
给定\(n\)个演员的姓名,问最多能按原顺序选出多少名演员,满足以下条件。
1.连续的两个演员中,一个演员的名字中带\(m\)字母,另一个演员的名字中不带\(m\)字母.
2.对于演员每个\(i\),对于演员\(j<i\),要保证\(s_i>=s_j \and reverse(s_i)>=reverse(s_j)\)
Sol
二维\(LIS\)+树状数组优化
设\(s_i\)为第一维,\(reverse(s_i)\)为第二维.
先按第一维的字典序从小到大排序,然后将第二维的字符串离散化.
则有了暴力的\(dp\)转移
\(dp[i][j]\)表示在前\(i\)个字符串中选取,且选取了第\(i\)个字符串有\(m\)或无\(m\)的最多合法人数.
如果当前字符串\(i\)不含有\(m\),\(dp[i][0]=\max_{j=0}^{i-1}(dp[j][1])+1\)
否则 \(dp[i][1]=\max_{j=0}^{i-1}(dp[j][0])+1\)
注意到取\(max\)的过程是前缀最大值关系,所以可以维护两个树状数组优化一下即可.
\(O(nlogn)\).
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=2e5+20;
const int M=1e5+10;
const int MAX=10000007;
inline int read() {
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
return x*f;
}
inline void out(int x) {
if(x>9) out(x/10);
putchar(x%10+'0');
}
/*
二维LIS 树状数组优化
*/
int t,n;
char s[N];
int vis[N];
string a[N],b[N],c[N];
int c1[N],c0[N];
int rk[N];
void add(int q[],int pos,int val){
while(pos<N){
q[pos]=max(q[pos],val);
pos+=lowbit(pos);
}
}
int get(int q[],int pos){
int ans=0;
while(pos){
ans=max(ans,q[pos]);
pos-=lowbit(pos);
}
return ans;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
rep(i,1,n+10)c1[i]=c0[i]=0;
rep(i,1,n)a[i].clear();
rep(i,1,n){
scanf("%s",s);
a[i]=s;
}
sort(a+1,a+1+n);
rep(i,1,n){
vis[i]=0;
rep(j,0,(int)a[i].size()-1){
vis[i]|=(a[i][j]=='m');
}
}
rep(i,1,n){
b[i]=a[i];
reverse(b[i].begin(),b[i].end());
c[i]=b[i];
}
sort(c+1,c+1+n);
int sz=unique(c+1,c+1+n)-(c+1);
rep(i,1,n){
rk[i]=lower_bound(c+1,c+1+sz,b[i])-c+1;
}
int mx=0;
rep(i,1,n){
if(vis[i]){
int p=get(c0,rk[i]);
mx=max(mx,p+1);
add(c1,rk[i],p+1);
}
else{
int p=get(c1,rk[i]);
mx=max(mx,p+1);
add(c0,rk[i],p+1);
}
}
printf("%d\n",mx);
}
return 0;
}