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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮