返回顶部

Codeforces Round #726 (Div. 2) E2. Erase and Extend (Hard Version) (字符串,思维.kmp)

  • 题意:给你一个字符串,选择一个前缀,使其不断复制,直到\(len>=k\),如果\(len>k\),删去多余的尾部,问你能得到的字典序最小的字符串.

  • 题解:基本思路和E1一样,比较后面的字符和\(s[1]\),大于就直接break,小于就继续,等于的话,我们要先找到\(s_{1...x}\)\(s_{i,i+1,..,i+x}\)的相同前缀,看第一个不相同的字符,如果\(s_{x+1}<s_{i+x+1}\)那么我们就继续选,否则直接break.这个相同前缀后第一个不同字符,不难发现,这不就是kmp找next数组的过程吗?直接s+s上kmp就行.

  • 题解:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n,k;
    string s;
    int ne[N];
    
    void get_nxt(){
    	for(int i=2,j=0;i<=2*n;++i){
    		while(j!=0 && s[i]!=s[j+1]) j=ne[j];
    		if(s[i]==s[j+1]) j++;
    		ne[i]=j;
    	}
    }
    
    int main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>k;
    	cin>>s;
    	s=" "+s+s;
    
    	get_nxt();
    
    	int len=n;
    
    	for(int i=1;i<=2*n;++i){
    		int j=ne[i-1]+1;
    		if(s[j]<s[i]){
    			len=i-j;
    			break;
    		}
    	}
    
    	for(int i=1,j=1;i<=k;++i){
    		cout<<s[j];
    		j++;
    		if(j>len) j=1;
    	}
    
        return 0;
    }
    
posted @ 2021-06-27 22:26  Rayotaku  阅读(76)  评论(0编辑  收藏  举报