G.残りの文字列を最大化する(思考+暴力的な列挙/単調なスタックの最適化)

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


題名:

小文字のみを含む長さnの文字列が与えられた場合、繰り返されるすべての文字(各文字に1つ)を削除し、残りの文字列を辞書式に最大にして、残りの文字列を出力します。n≤2×10 ^ 5

アイデア:

暴力を振るう可能性がある場合は、まず暴力について考えてください。

答えの長さは最大で26であることがわかりました。したがって、最初にさまざまな種類の文字の数を数え、答えの長さはそのサイズです。

次に、答えの各ビットについて、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

この問題は、単調なスタック最適化を使用することです。

数字を削除するのはコツのようです

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

更新予定

おすすめ

転載: blog.csdn.net/zstuyyyyccccbbbb/article/details/115258141