C. K-beautiful Strings

题目链接

题目大意: 给出你长度为n的字符串s,构造出一个大于等于s,长度为n的字符串ans,使得字符串ans中的出现的字符次数能整除m。
思路: 建立(构造) 一个后缀连续字符数组(为了缩短后面的判断时间)
dp[i][j] 表示第i位上后面(dp[i][j]-1)个‘a’+j字符,就是连续。
用flag表示是否已经满足“大于字符串这一条件”

  1. 不满足,枚举当前位能放的字符(大于等于当前字符),之后判断是否还有该字符可用(我们每次开一个字符都是k个的开,这样可以直接满足字符数量被k整除) (1)没有可用的,开一个新k组该字符还有(k-1)个可用,总可用数量减k。然后判断是否大于原串。(2) 有可用的就直接用。
  2. 满足之后,剩下的全部都变成’a’。因为每次取得是k。所以剩的也是k得倍数。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
char a[maxn];
int n,k,b[30],c[30],las[maxn][27],top;
char ans[maxn];
bool isok(int nxt,int c[]) {
    
    
    while( nxt<=n ) {
    
    
        for(int i='z'; i>='a'; i--) {
    
    
            if( c[i-'a']==0 )	continue;///已满或者没有
            if( i>a[nxt] )	return true;///已经比较大了
            else if( i<a[nxt] )	return false;///当前位置比原小
            else if( c[i-'a']>=las[nxt][i-'a'] ) {
    
    ///够后面用的 连续
                c[i-'a'] -= las[nxt][i-'a'], nxt += las[nxt][i-'a'];
                break;
            } else if( c[i-'a']<las[nxt][i-'a'] )	return false;///不够
        }
    }
    return true;//一直相等,也是合法的
}
int main() {
    
    
    int t;
    cin >> t;
    while( t-- ) {
    
    
        cin >> n >> k >> ( a+1 );
        if( n%k!=0 )	{
    
    
            cout << -1 << endl;
            continue;
        }
        for(int i=n; i>=1; i--)
            for(int j='a'; j<='z'; j++) {
    
    
                if( a[i]==j )	las[i][j-'a'] = las[i+1][j-'a']+1;///后续连续字符
                else	las[i][j-'a'] = 0;
            }

        int flag = 1,sum = n;///flag来判断是否已经满足大于要求
        for(int i=1; i<=n; i++) {
    
    
            if( flag ) {
    
    ///未满足
                for(char j=a[i]; j<='z'; j++) {
    
    ///枚举大于等于当前字符
                    if( b[j-'a'] ) {
    
    ///可用数量
                        memcpy( c,b,sizeof c );
                        c[j-'a']--;///放 j这个字符
                        c['z'-'a'] += sum;///剩下的都变成z字符
                        if( j>a[i] || isok(i+1,c) ) {
    
    
                            ans[i] = j;
                            b[j-'a']--;
                            if( j>a[i] )	flag = 0;
                            break;
                        }
                    } else {
    
    
                        if( sum<k )	continue;///剩下的不够新增字符的,
                        memcpy( c,b,sizeof c );
                        c[j-'a'] += k-1;
                        c['z'-'a'] += sum-k;///用最大的情况判断是否可行。
                        if( j>a[i] || isok(i+1,c) ) {
    
    
                            ans[i] = j;
                            sum -= k;
                            b[j-'a'] = k-1;
                            if( j>a[i] )	flag = 0;
                            break;
                        }
                    }
                }
            } else {
    
     ///字典序已经比较大了,后面怎样都无所谓,那么从'a'开始一直往后面放
                b[0] += sum;
                int id = i;
                for(char j='a'; j<='z'; j++)	while( b[j-'a'] )	ans[id++]=j, b[j-'a']--;
                break;
            }
        }
        for(int i=1; i<=n; i++)	cout << ans[i];
        cout << endl;
        for(int i=1; i<=n; i++)	memset( las[i],0,sizeof las[i] );
        memset( b,0,sizeof b );
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45911397/article/details/114685175
今日推荐