Tear It Apart CodeForces - 1821C

212 阅读2分钟

题意:我们可以进行一个操作,一次删除一个或多个字符,但删除的字符不可以相邻

求对所给字符我们要进行最少几次从而形成相同字符组成的串串(且最长)

解:

当我们想要使得两个字符靠近,先要看她两之间隔着几个无关字符,假设隔了N个,那么由于每次删除的字符不能相邻(至少也要隔一个),所以最少通过log2(N)+1次来消除她们之间的无关字符。

又因为总共最多也才26个字母,我们可以对每个字母判断一遍(最少几次使得字符串中的该字母靠在一起)

如何判断最少几次使得字符串中的该字母靠在一起呢?

找出最大的相邻(理论上相邻,就是第一个a和第二个a,第二个a和第三个a之间的距离这个意思的相邻)该字母之间的字符个数。如果能把隔最远的两个相邻该字母靠近,那么其他的就一定能消除。所以就能得到得到该字母串的最小次数。

再求出每个字母串中的最小操作次数就是我们需要的答案。

这里我们进行了一个转换,就是用一个二维数组的一维存储当前字符是谁(通过-'a'换成0~26数字),用它的二维(也就相当于每一行)存储该字母出现的下标。

遍历一遍就可以完成这个操作:

然后我们通过每个字母存储的下标逐个计算长度,找组内最大长度,组间最小操作次数即可。

所以该题:

#include<bits/stdc++.h>
using namespace std;
int t,l,n,ans,maxl;
string s;
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>s;
        n=s.size();
        vector<int> a[30];//二维数组
        for(int i=0; i<n; i++)
            a[s[i]-'a'].push_back(i);//记录每个字符的下标到对于数组中
        ans=n;//结果
        for(int i=0; i<26; i++)
        {
            l=-1;
            maxl=0;//组内最长
            a[i].push_back(n);
            for(int j=0; j<a[i].size(); j++)
            {
                int len = a[i][j]-l-1;
                if(len>=1)
                {
                    int lens=log2(len)+1;
                    maxl=max(maxl,lens);
                }
                l=a[i][j];
            }
            ans=min(ans,maxl);
        }
        cout<<ans<<endl;//取最小操作数
    }
    return 0;
}