C.K-美しい弦

トピックリンク

トピックの主なアイデア:長さnの文字列sが与えられた場合、文字列ansの文字数をmで割れるように、s以上の長さnの文字列ansを作成します。
アイデア:接尾辞付きの連続する文字の配列を作成(構築)します(後で判断時間を短縮するため)
dp [i] [j]は(dp [i] [j] -1) 'a' + j文字を表しますi番目の位置では、連続しています。
フラグを使用して、「文字列より大きい条件」が満たされているかどうかを示します

  1. 満足できない場合は、現在の位置に配置できる文字(現在の文字以上)を列挙し、まだ使用可能な文字があるかどうかを判断します(開くたびに文字を開くので、文字数は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