1. 程式人生 > 其它 >Codeforces Round #726 (Div. 2) E2. Erase and Extend (Hard Version) (字串,思維.kmp)

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;
    }