给定一个长度为 的 01 串,求最多可以选出多少互不相交的子串,满足这些子串按照原串中的顺序,字典序严格升序。
。
不要再自然根号了。
设最终选出的子串为 ,则 ,必定有 。
并且必定有 。
那么不难得出, ,因为对于所有 都必定存在 满足 。
所以 。
那么设 表示 的答案,把所有长度 的子串都拉出来放到 trie 上,用树状数组维护 的转移即可。
答案即为 ,时间复杂度 。
代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int S=25005,M=250,MS=10000005;
int n;
char a[S];
int cnt,son[MS][2];
vector<pair<int,int>> idx[MS];
int c[S],f[S];
inline void addt(int u,int val)
{
for(int i=u;i<=n;i+=i&-i) c[i]=max(c[i],val);
}
inline int quet(int u)
{
int res=0;
for(int i=u;i>=1;i-=i&-i) res=max(res,c[i]);
return res;
}
void dfs(int u)
{
for(auto u:idx[u])
{
int l=u.first,r=u.second;
f[r]=max(f[r],quet(l-1)+1);
addt(r,f[r]);
}
if(son[u][0]!=0) dfs(son[u][0]);
if(son[u][1]!=0) dfs(son[u][1]);
}
int main()
{
scanf("%d%s",&n,a+1);
for(int i=n;i>=1;i--)
{
int u=0;
for(int j=i;j<=n&&j<=i+M-1;j++)
{
int id=a[j]-'0';
if(son[u][id]==0) son[u][id]=++cnt;
u=son[u][id];
idx[u].push_back({i,j});
}
}
dfs(0);
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d\n",ans);
return 0;
}