题解:AT_abc416_g [ABC416G] Concat (1st)
提示:这篇题解中部分内容借鉴了官方题解的思路,但是相较而言省略了部分推导过程,直接进入做法部分。
首先,我们有一些前置的约定/定义:
-
以下的所有大写字母代表字符串;
-
-
-
-
以下设
n,k 同阶。
我们考虑套路地定义一种全序关系:字符串
举例而言,当 a,ab 的时候,
下面所说的字符串之间的比较,都以这种全序关系为准。
现在,我们给出本题的一个重要结论:答案串一定是
官方题解中对此给出了严谨的证明以及循序渐进的推导过程,但是我个人倾向于在赛时通过观察样例发现这一点(这个性质其实非常自然)。当然也可以这么理解:我们刚刚定义的全序关系使得答案串无法找到一个位置满足它与
这样,我们有了这条性质,就只需要找到可以构造出的前缀中最短的即可。可以考虑 dp,设
这里可以使用字符串哈希,当然也可以用 map 直接实现,复杂度为
代码仅作参考,跑了九百多毫秒,不能要了。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
string s[N],t;
int dp[N];
int n,k;
map<string,int>mp;
signed main(){
memset(dp,0xcf,sizeof dp);
ios::sync_with_stdio(0);
cin.tie(nullptr);
cout.tie(nullptr);
cin>>n>>k;
for(int i=1;i<=n;++i){
cin>>s[i];
mp[s[i]] = 1;
}
sort(s+1,s+n+1,[&](auto x,auto y){
return (x+y<y+x) || (x<y && x+y==y+x);
});
string S = " ";
for(int i=1;i<=k;++i) S += s[1];
dp[0] = 0;
for(int i=1;i<(int)S.size();++i){
string cur;
for(int j=i;j>=i-10 && j;--j){
cur = S[j] + cur;
if(mp[cur]) dp[i] = max(dp[i],dp[j-1]+1);
}
cout<<S[i];
if(dp[i]==k) return 0;
}
return 0;
}