C. K-beautiful Strings

Topic link

The main idea of ​​the topic: Given your string s of length n, construct a string ans that is greater than or equal to s and length n, so that the number of characters in the string ans can be divided by m.
Idea: Create (construct) an array of consecutive characters with a suffix (in order to shorten the judgment time later)
dp[i][j] represents the (dp[i][j]-1)'a'+j characters on the i-th position , Is continuous.
Use flag to indicate whether the "condition of greater than string" has been met

  1. If not satisfied, enumerate the characters that can be placed in the current position (greater than or equal to the current character), and then judge whether there is still the character available (we open a character every time we open, so that the number of characters can be directly divided by k) (1) If there is no available, open a new k group of the characters and (k-1) available, the total available number is reduced by k. Then determine whether it is greater than the original string. (2) Use it as it is available.
  2. After being satisfied, all the rest becomes'a'. Because it is k each time. So what is left is also a multiple of 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 );
    }
}

Guess you like

Origin blog.csdn.net/weixin_45911397/article/details/114685175