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
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
AC × 3
AC × 29
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