CF1530E Minimax

\(CF1530E\ Minimax\)

题意

给一个字符串 \(s\),要求将 \(s\) 重新排列得到 \(t\),使得:

  • 对于 \(t\) 的每个前缀 \(i\),定义 \(f(i)\) 为前缀 \(i\)\(border\),使得所有位置的 \(f(i)\) 最大值最小

  • 满足条件的 \(t\) 的字典序最小

思路分析

思路其实很简单清晰,即:

然后瞎推就完了

首先不难发现一个结论:

对于任意串 \(s\),当 \(s\) 中存在至少2种字符时,必然存在 \(t\) 使得 \(f(t)=0\)\(1\).

证明将在下文中体现。

然后约定几个变量:

  1. \(st\)\(s\) 中出现的字典序最小的字符。
  2. \(se\)\(s\) 中出现的字典序第二小的字符(如果存在至少两种字符)。
  3. \(th\)\(s\) 中出现的字典序第三小的字符(如果存在至少三种字符)。
  4. \(cnt[c]\)\(s\) 中字符 \(c\) 出现的次数。
  5. \(kinds\)\(s\) 中字符种数。
for(int i='a';i<='z';i++)  cnt[i]=0;
st='z'+1;int kinds=0;
scanf(" %s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++){
    if(!cnt[s[i]])  kinds++;
    cnt[s[i]]++;
    st=min(st,s[i]);
}

那么,开始酣畅淋漓的分讨特判吧~


壹.特判 \(f(t)=0\).

不难发现,当且仅当 \(\exists \ i,cnt[i]=1\) 时,能够满足 \(f(i)=0\).比如串\(s=\)"\(bababc\)",\(t\) 显然为 "caabbb".

code

bool b=0;
for(int i='a';i<='z';i++){
    if(cnt[i]==1){
        pc(i);--cnt[i];
        for(int j='a';j<='z';j++)
            while(cnt[j]-->0)  pc(j);
        b=1;pt;break;
    }
}
if(b)  continue;

贰.特判 \(kinds=1\)

直接输出即可.

if(kinds==1){
    for(int i=1;i<=n;i++)  pc(st);
    pt;continue;
}

叁.对于 \(f(t)=1\) 进行分讨

1. \(kinds=2\)

为了让字典序最小,显然要先尽可能多地输出 \(st\) (最多显然是\(2\)个),那么为了让 \(f(t)=1\),接着分讨。

  • \(cnt[st]=2\) 时,例如"\(abbabbb\)",直接按字典序输出即可,即"\(aabbbbb\)"

  • \(cnt[st]=3\) 时,例如"\(abbaabb\)",考虑先输出 \(2\)\(st\),再用 \(se\) 分割一下,输出剩下的一个 \(st\),再输出剩下的 \(se\),即"\(aababbb\)"

  • \(cnt[st]>3\) 时,我们分讨要先输出几个 \(st\).

    • \(cnt[st]-1>cnt[se]+1\) 时,例如"\(aabbaaaa\)"不难发现此时 \(st\) 一定会连着出现至少两次,(考虑用 \(se\) 分割),如果用两个 \(st\) 开头,必然会令 \(f(t)=2\),(比如"\(aababaaa\)")。所以必然要以一个 \(st\) 开头。然后输出所有 \(se\),(至于为什么输出所有的,显然 \(f(abaaaabb)=2\)),最后输出剩下的 \(st\),即"\(abbaaaaa\)"

    • \(cnt[st]-1 \leq cnt[se]+1\) 时,例如"\(aabaabbbb\)"不难发现此时 \(st\) 可以被 \(se\) 分隔开使得没有 \(st\) 相邻,那么为了让字典序最小,我们用两个 \(st\) 开头,接着循环输出"\(se\ st\ se\ st \dots\)"即可。另外,由于 \(cnt[st]-2 < cnt[se]\) 所以剩下的一定是 \(se\)。输出即可。即"\(aabababbb\)".

code

for(se=st+1;se<='z';se++)  if(cnt[se])  break;
if(kinds==2){
    if(cnt[st]==2){
        pc(st),pc(st),cnt[st]-=2;
        while(cnt[se]-->0)  pc(se);
    }
    else if(cnt[st]==3){
        pc(st),pc(st),cnt[st]-=2;
        pc(se),--cnt[se];
        pc(st),--cnt[st];
        while(cnt[se]-->0)  pc(se);
    }
    else{
        if(cnt[st]-1>cnt[se]+1){
            pc(st);cnt[st]--;
            while(cnt[se]-->0)  pc(se);
            while(cnt[st]-->0)  pc(st);
        }
        else{
            pc(st),pc(st),cnt[st]-=2;
            while(cnt[st] && cnt[se]){
                pc(se),pc(st);
                --cnt[st];--cnt[se];
            }
            while(cnt[se]-->0)  pc(se);
        }
    }
    pt;continue;
}

2. \(kinds \geq 3\)

  • \(cnt[st]==2\) 以及 \(cnt[st]==3\) 时,方法同上。

  • \(cnt[st]>3\) 时,与上文类似的,令 \(els=n-cnt[st]\).讨论:

    • \(cnt[st]-1>els+1\) 时,例如"\(aabbaaacaac\)",上文已证,应使用一个 \(st\) 开头,然后用一个 \(se\) 分隔,接着输出所有 \(st\) ,为了不重复出现"\(st\ se\)",我们再用 \(th\) 分隔,然后以字典序输出剩下所有字符,即"\(abaaaaaacbc\)".

    • \(cnt[st]-1\leq els+1\) 时,例如"\(aababcabc\)",上文已证,应使用两个 \(st\) 开头,然后用剩下的其他字符将剩下的 \(st\) 分隔输出,输出完 \(st\) 后按字典序输出剩下的其他字符即可。即"\(aabababcc\)".

code

if(kinds>=3){
    if(cnt[st]==2){
        pc(st),pc(st),cnt[st]=0;
        for(int i=st+1;i<='z';i++)
            if(cnt[i])
                while(cnt[i]-->0)  pc(i);
    }
    else if(cnt[st]==3){
        pc(st),pc(st);
        pc(se),--cnt[se];
        pc(st);cnt[st]=0;
        for(int i=st+1;i<='z';i++)
            if(cnt[i])
                while(cnt[i]-->0)  pc(i);
    }
    else{
        int els=n-cnt[st];
        if(cnt[st]-1>els+1){
            pc(st);--cnt[st];
            pc(se);--cnt[se];
            while(cnt[st]-->0)  pc(st);
            pc(th);--cnt[th];
            for(int i=st+1;i<='z';i++)
                if(cnt[i])
                    while(cnt[i]-->0)  pc(i);
        }
        else{
            pc(st),pc(st),cnt[st]-=2;
            for(int i=st+1;i<='z';i++){
                while(cnt[i] && cnt[st])
                    pc(i),pc(st),--cnt[i],--cnt[st];
                if(!cnt[st])
                    while(cnt[i]-->0)  pc(i);
            }
        }
    }
    pt;
}

真是一场酣畅淋漓的分讨啊

\(AC\ \ code\)

#include<bits/stdc++.h>
using namespace std;

#define pc putchar
#define read read()
#define pt puts("")
inline int read
{
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')  f=-1;c=getchar();}
    while(c>='0'&&c<='9')   x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return f*x;
}
void write(int x)
{
    if(x<0)  pc('-'),x=-x;
    if(x>9)  write(x/10);
    pc(x%10+'0');
    return;
}
#define N 100010
int q,n;
char s[N];
int cnt[130];
char st='z'+1,se,th;
signed main()
{
    #ifndef ONLINE_JUDGE
        freopen("lty.in","r",stdin);
        freopen("lty.out","w",stdout);
    #endif
    q=read;
    while(q-->0){
        for(int i='a';i<='z';i++)  cnt[i]=0;
        st='z'+1;int kinds=0;
        scanf(" %s",s+1);
        n=strlen(s+1);
        for(int i=1;i<=n;i++){
            if(!cnt[s[i]])  kinds++;
            cnt[s[i]]++;
            st=min(st,s[i]);
        }
        bool b=0;
        for(int i='a';i<='z';i++){
            if(cnt[i]==1){
                pc(i);--cnt[i];
                for(int j='a';j<='z';j++)
                    while(cnt[j]-->0)  pc(j);
                b=1;pt;break;
            }
        }
        if(b)  continue;
        if(kinds==1){
            for(int i=1;i<=n;i++)  pc(st);
            pt;continue;
        }
        for(se=st+1;se<='z';se++)  if(cnt[se])  break;
        if(kinds==2){
            if(cnt[st]==2){
                pc(st),pc(st),cnt[st]-=2;
                while(cnt[se]-->0)  pc(se);
            }
            else if(cnt[st]==3){
                pc(st),pc(st),cnt[st]-=2;
                pc(se),--cnt[se];
                pc(st),--cnt[st];
                while(cnt[se]-->0)  pc(se);
            }
            else{
                if(cnt[st]-1>cnt[se]+1){
                    pc(st);cnt[st]--;
                    while(cnt[se]-->0)  pc(se);
                    while(cnt[st]-->0)  pc(st);
                }
                else{
                    pc(st),pc(st),cnt[st]-=2;
                    while(cnt[st] && cnt[se]){
                        pc(se),pc(st);
                        --cnt[st];--cnt[se];
                    }
                    while(cnt[se]-->0)  pc(se);
                }
            }
            pt;continue;
        }
        for(th=se+1;th<='z';th++)  if(cnt[th])  break;
        if(kinds>=3){
            if(cnt[st]==2){
                pc(st),pc(st),cnt[st]=0;
                for(int i=st+1;i<='z';i++)
                    if(cnt[i])
                        while(cnt[i]-->0)  pc(i);
            }
            else if(cnt[st]==3){
                pc(st),pc(st);
                pc(se),--cnt[se];
                pc(st);cnt[st]=0;
                for(int i=st+1;i<='z';i++)
                    if(cnt[i])
                        while(cnt[i]-->0)  pc(i);
            }
            else{
                int els=n-cnt[st];
                if(cnt[st]-1>els+1){
                    pc(st);--cnt[st];
                    pc(se);--cnt[se];
                    while(cnt[st]-->0)  pc(st);
                    pc(th);--cnt[th];
                    for(int i=st+1;i<='z';i++)
                        if(cnt[i])
                            while(cnt[i]-->0)  pc(i);
                }
                else{
                    pc(st),pc(st),cnt[st]-=2;
                    for(int i=st+1;i<='z';i++){
                        while(cnt[i] && cnt[st])
                            pc(i),pc(st),--cnt[i],--cnt[st];
                        if(!cnt[st])
                            while(cnt[i]-->0)  pc(i);
                    }
                }
            }
            pt;
        }
    }
    return 0;
}

\(CF\)*\(2100\) 难度,比起题单上其他题,真是挺水。

posted @ 2024-04-13 15:31  lty_ylzsx  阅读(8)  评论(1编辑  收藏  举报