这道题老师有一天断了网让我们做,然后线下测评开了2s。。。
当时我是手打几个数据,然后找到规律的。
对于$s_i$,我们分情况讨论:
首先,如果有$s_i=s_{i+1}$,那么删除$s_i$和$s_{i+1}$结果一样,那么可以把连续相同字符压成一个,输出时从小到大输出就可以了。
然后,如果有$s_i>s_{i+1}$,那么删除$s_i$肯定比不删除$s_i$更优,所以$i$排在所有$k(>i)$的前面。
最后,如果有$s_i<s_{i+1}$,那么删除$s_i$肯定没有不删除$s_i$优,所以$i$排在所有$k(>i)$的后面。
我是用一次$dfs$解决的,只要到一个连续下降子序列(压缩后无相邻相等)的末尾就往下$dfs$在回溯时再输出当前位置,边界为到达$N$。
Code:
#include<cstdio>
int N,bg[1000003],cnt;//bg:begin,一个连续相同序列的开始
char s[1000003];
inline void dfs(int d)
{
int t,m;
for(t=d;s[bg[t]]>s[bg[t+1]];++t)
{
for(m=bg[t];m<bg[t+1];++m)
{
printf("%d ",m); } if(m==N+1)return; } dfs(t+1);//回溯后再输出当前位置 for(m=bg[t];m<bg[t+1];++m) { printf("%d ",m); } } int main() { scanf(" %d %s",&N,s+1); for(int i=1;i<=N;++i) { if(s[i]==s[i-1])continue; bg[++cnt]=i;//压缩 } bg[++cnt]=N+1; dfs(1); return 0; }