CF1562E

· · 题解

首先,容易发现,s[i,j+1] 的字典序一定大于 s[i,j],所以,s[i,j] 后面一定能接上 s[i,j+1]

有一个结论,一定存在一种答案最优的选择方案,使得,若 s[i,j] 被选了,则 s[i,j+1 \sim n] 也被选。下面证明这个结论。

假设 s[i,j \sim k] 全都选了,s[i,k+1] 忽然不选了。考虑在什么情况下才会导致这样改变选择。显然,一定存在一对 l,r,使得 l>is[l,r] > s[i,k]s[l,r] < s[i,k+1]

首先,一定有 s[l,r-1]=s[i,k]

s[l,r-1]<s[i,k],则显然在 k 更小的时候就可以改变选择了,得到的答案一定不会比现在劣。若 s[l,r-1]>s[i,k],则一定有 s[l,r]>s[i,k+1]。不满足定义的条件。

既然如此,选 s[i,k] 就可以视作是选了 s[l,r-1],并从 s[l,r] 开始继续往后选。可以把这个理解为一个“继承”的过程,一定会不断“继承”,直到选上了一个 s[x,n](否则,答案一定不优)。总的来看,就可以认为我们选择了 s[x,y \sim n]

这样一个“继承”的过程就包含了所有可能会使答案更优的改变选择的情况,至此,结论证毕。所以,只需考虑所有以 s[i,n] 为结尾的 LIS 即可。

\operatorname{lcp}(i,j) 表示满足 s_{i+k}s_{j+k} 不相等的最小的 k,令 f_i 表示以 s[i,n] 为结尾的 LIS。

s_{i+\operatorname{lcp}(i,j)}>s_{j+\operatorname{lcp}(i,j)},则 f_i 是可以由 f_j 转移过来的,转移为:f_i=(n-i+1)+\max \limits_{1 \leq j <i}\{f_j-\operatorname{lcp}(i,j)\}

```cpp #include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N=5010; int T,n,f[N]; int lcp[N][N]; char s[N]; int MAX(int x,int y) { return x>y?x:y; } int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); scanf("%s",s+1); for(int i=1;i<n;i++) lcp[i][n]=(s[i]==s[n]); for(int j=n-1;j>=1;j--) for(int i=j-1;i>=1;i--) { if(s[i]==s[j]) lcp[i][j]=lcp[i+1][j+1]+1; else lcp[i][j]=0; } for(int i=1;i<=n;i++) f[i]=n-i+1; for(int i=2;i<=n;i++) for(int j=1;j<i;j++) if(s[i+lcp[j][i]]>s[j+lcp[j][i]]) f[i]=MAX(f[i],f[j]+n-i+1-lcp[j][i]); int ans=0; for(int i=1;i<=n;i++) ans=MAX(ans,f[i]); printf("%d\n",ans); } return 0; } ```