Submission #43460450
Source Code Expand
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<(int)n;i++)
#define per(i,a,n) for (int i=n;i-->(int)a;)
int read(){int r;scanf("%d",&r);return r;}
const int K = 10000;
const int N = 2000;
bitset<K+10> can[N+10]; // can[i...n][长度] = bool(后面i..n的字符能否品出 长度)
bitset<K+10> dp[N+10]; // dp[1..i][长度] = bool(可能对答案贡献(后缀长度可能+前缀最小),且前缀1..i 可拼成
string ans[2]; // ans[i] = 处理完前i个 最长的 可能的 字符串, 滚动i&1
string&cs(int i){return ans[i&1];}
vector<string> arr;
char tmp[K+10];
vector<int> make_z(const string&s) {
int l = 0; // 保持r最大
int n = size(s);
vector<int> z(n,0);
rep(i,1,n) {
int r = l + z[l] - 1;
z[i] = max(0,min(r-i+1,z[i-l]));
while(i + z[i] < n and s[i + z[i]] == s[z[i]]) z[i]++;
if(i + z[i] - 1 > r) l = i;
}
z[0] = n;
return z;
}
// prefix[p] vs prefix[q] + arr[j]
int cmp(const vector<int>&z,int i, int p, int q) {
// [............]
// [........p]..]
// [.....q][si....]
const int szs = size(arr[i]);
if (p <= q) return 0;
int lcp = z[szs + q];
if (lcp >= szs || q + lcp >= p) return 0;
return (cs(i-1)[q + lcp] < arr[i][lcp]) ? -1 : 1;
}
// sign( (ans[i-1][0..p] + s[i])
// - (ans[i-1][0..q] + s[i]))
// < -1, = 0, > 1
int cmp2(const vector<int>&z,int i,int p, int q) { // p,q 0-index
// z = s[i] + '$' + ans[i-1]
// [.....p][si......]
// [..........q][si......]
// [ ] lcp(si,ans[i-1][p+1..q])
// [ ] lcp(si,si[q-p..])
//z: 0 szs-1
// szs+1
int szs = size(arr[i]);
if (p > q) return -cmp2(z,i, q, p);
int lcp = z[szs + p]; // lcp(si,ans[i-1][p+1..q])
if (lcp < q - p) {
if (lcp >= szs) return 0;
return (cs(i-1)[p + lcp] < arr[i][lcp]) ? -1 : 1;
}
lcp = z[q - p]; // lcp(si,si[q-p..])
if (q + lcp >= p + szs) return 0;
return (arr[i][lcp] < arr[i][q - p + lcp]) ? -1: 1;
}
int main() {
int n=read();
int k=read();
arr.resize(n+1); // 1-index
rep(i,1,n+1) {
scanf("%s",tmp);
int sz=strlen(tmp);
rep(j,0,sz) arr[i].push_back(tmp[j]);
}
can[n + 1][0] = 1;
// Zeroes are shifted in, and bits that would go to an index out of range are dropped (ignored).
per(i,1,n+1) can[i] = can[i + 1] | (can[i + 1] << (int)size(arr[i]));
dp[0][0] = 1;
rep(i,1,n+1){
// 不使用j的情况
cs(i) = cs(i - 1);
per(j,0,k+1) if(dp[i-1][j] and can[i+1][k-j]) { // 对于上一个成立,对于当前不使用, 可能不成立
cs(i) = cs(i).substr(0,j); // 先只用关心最长的即可
break;
}
const int sz = size(arr[i]);
auto z = make_z(arr[i] + cs(i - 1)); // [0..sz-1][sz..sz+len(cs(i-1))-1]
z.push_back(0); // cmp2 中 z[q-p] 可能超长
// decide cs[i]
int nxt = -1; // 只记录合成的(prefix[ans[i-1]] + s[i])最优的
rep(j,0,k-sz+1) if (dp[i-1][j] and can[i+1][k-(j+sz)]) { // j => j+sz
if (nxt == -1) { // 暂无方案
int res = cmp(z,i,size(cs(i)), j); // 和 转移过来的 方案比
if (res == 1 || (res == 0 and j + sz > (int)size(cs(i)))) nxt = j; // 更小,或前缀相等但是更长
} else if (cmp2(z,i, nxt, j) <= 0){
nxt = j;
}
}
if (nxt == -1) {// s[i] is not a suffix of cs[i]
// 对于上一个成立, 对于当前不使用, 可能不成立,
// 这种状态不清理其实也不影响,因为后面拼接时也有校验,不会产生贡献
rep(j,0,k+1) if(dp[i-1][j] and can[i+1][k-j]) dp[i][j] = 1;
} else {
// ans [.............]
// [.....nxt][si.....]
// | 匹配以后的0/1会变
cs(i) = cs(i - 1).substr(0, nxt) + arr[i];
// 和原来相等的部分
rep(j,0,size(cs(i - 1))+1) dp[i][j] = (dp[i - 1][j] and can[i+1][k-j] and cmp(z,i, j, nxt) == 0);
dp[i][size(cs(i))] = 1;
// 又 前面 的 + arr[i] 拼成
rep(j,0, size(cs(i)) - sz) if(dp[i - 1][j] and can[i+1][k-sz-j] and cmp2(z,i,j,nxt) == 0)dp[i][j+sz]=1;
}
}
printf("%s\n",cs(n).c_str());
return 0;
}
Submission Info
Submission Time
2023-07-10 20:55:49+0900
Task
F - Iroha Loves Strings
User
cromarmot
Language
C++ (GCC 9.2.1)
Score
1500
Code Size
4091 Byte
Status
AC
Exec Time
254 ms
Memory
10456 KiB
Compile Error
./Main.cpp: In function ‘int read()’:
./Main.cpp:5:23: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
5 | int read(){int r;scanf("%d",&r);return r;}
| ~~~~~^~~~~~~~~
./Main.cpp: In function ‘int main()’:
./Main.cpp:70:10: warning: ignoring return value of ‘int scanf(const char*, ...)’, declared with attribute warn_unused_result [-Wunused-result]
70 | scanf("%s",tmp);
| ~~~~~^~~~~~~~~~
Judge Result
Set Name
Sample
All
Score / Max Score
0 / 0
1500 / 1500
Status
Set Name
Test Cases
Sample
0_sample01, 0_sample02, 0_sample03
All
0_sample01, 0_sample02, 0_sample03, abab0, abten0, allsame0, allsame_ex0, bigrand0, bigrand1, firstlast0, firstlast1, fullrand0, fullrand1, fullrand2, kaidan0, maxrand0, maxrand1, maxrand2, roll_hyper0, roll_hyper1, roll_hyper_r0, rolling0, rolling1, smallc0, smallc1, smallrand0, smallrand1, smallrand2, zzza0
Case Name
Status
Exec Time
Memory
0_sample01
AC
8 ms
3704 KiB
0_sample02
AC
2 ms
3664 KiB
0_sample03
AC
3 ms
3696 KiB
abab0
AC
115 ms
7972 KiB
abten0
AC
117 ms
9640 KiB
allsame0
AC
254 ms
9332 KiB
allsame_ex0
AC
252 ms
9100 KiB
bigrand0
AC
52 ms
7640 KiB
bigrand1
AC
74 ms
8672 KiB
firstlast0
AC
85 ms
9660 KiB
firstlast1
AC
85 ms
9704 KiB
fullrand0
AC
64 ms
9624 KiB
fullrand1
AC
80 ms
9668 KiB
fullrand2
AC
72 ms
9640 KiB
kaidan0
AC
224 ms
9504 KiB
maxrand0
AC
68 ms
9172 KiB
maxrand1
AC
72 ms
9312 KiB
maxrand2
AC
73 ms
9212 KiB
roll_hyper0
AC
134 ms
10436 KiB
roll_hyper1
AC
130 ms
10456 KiB
roll_hyper_r0
AC
134 ms
10308 KiB
rolling0
AC
129 ms
10068 KiB
rolling1
AC
128 ms
9936 KiB
smallc0
AC
40 ms
9048 KiB
smallc1
AC
41 ms
9048 KiB
smallrand0
AC
6 ms
3628 KiB
smallrand1
AC
2 ms
3640 KiB
smallrand2
AC
2 ms
3704 KiB
zzza0
AC
82 ms
8420 KiB