G. Maximize the Remaining String(思维+暴力枚举/单调栈优化)

https://codeforces.com/contest/1506/problem/G


题意:

给出一个长度为 n的只包含小写字母的字符串要删掉其中的所有重复字符(每个字符必须留一个),使留下来的字符串字典序最大,输出留下的字符串。 n≤2×10^5

思路:

能暴力就先思考暴力。

我们发现答案最多是长度为26的。于是先统计不同种类字母个数,答案长度就是其size。

然后对于答案的每一位,我们可以O(26)枚举每一个字符。然后考虑,当前字符如果选了,后面的不同字符的种类个数够不够。够的话就选。不够的话就继续枚举。

于是快速判断后面不同字符的种类够不够,后缀预处理。

O(26*26*n)==1e8 (2.5s)够

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2e5+1000;
typedef int LL;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
char str[maxn];
LL sum[maxn];///后缀不同种类数字的个数
bool st[maxn][30];///后缀每个种类数字的存在状态
bool del[maxn];
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--){
     cin>>(str+1);
     LL n=strlen(str+1);
     for(LL i=0;i<n+10;i++) sum[i]=0,del[i]=0;
     for(LL i=0;i<n+10;i++){
        for(LL j=0;j<=29;j++) st[i][j]=0;
     }
     for(LL i=n;i>=1;i--){
         sum[i]=sum[i+1];
         for(LL j=1;j<=26;j++){
            st[i][j]=st[i+1][j];
         }
         if(st[i][str[i]-'a'+1]==0){
            st[i][str[i]-'a'+1]=1;
            sum[i]++;
         }
     }
     LL m=sum[1];
     vector<char>v;
     LL op=1;
     for(LL l=1;l<=m;l++){
        for(char c='z';c>='a';c--){
            if(st[op][c-'a'+1]==false) continue;
            bool flag=0;
            for(LL i=op;i<=n;i++){
                if(flag){
                    if(st[i][c-'a'+1]==1){
                        st[i][c-'a'+1]=0;
                        sum[i]--;
                    }
                    if(str[i]==c) del[i]=1;
                }
                if(del[i]) continue;
                if(str[i]==c){
                    LL temp=sum[i+1];///后面的有效种类个数
                    if(st[i+1][c-'a'+1]) temp--;///如果涵盖当前字母,--;
                    if(temp>=m-l){
                        flag=1;
                        op=i+1;
                    }
                }
            }
            if(flag){
                v.push_back(c);
                break;
            }
        }
     }
     for(auto i:v){
        cout<<i;
     }
     cout<<"\n";
  }
return 0;
}

后来群里说是道原题。

https://ac.nowcoder.com/acm/contest/12606/E

这道题就是要用单调栈优化的。

好像还是个删数问题的trick

https://codeforces.ml/gym/102890/problem/M

待update

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/115258141