Official

E - ダンスの同期 / Dance Synchronization Editorial by kyopro_friends


まず修正を行わない場合を考えます。
ペアの個数の最大値は、\(s,t\) の LCS (最長共通部分列) の長さになります。これは \(\mathrm{DP}[i][j]\) を「 \(s\)\(i\) 文字目までからなる文字列と、 \(t\)\(j\) 文字目までからなる文字列の LCS の長さ」と定める動的計画法により \(O(|s||t|)\) で求めることができます。

修正を行う場合を考えます。
\(s\) には同じ文字が \(3\) 回以上連続する箇所が存在しないことから、\(s\) の先頭でも末尾でもない文字を変更することはできません。\(t\) も同様なので、「\(s,t\) の先頭・末尾をそれぞれ変更するかどうか」の \(2^4\) 通りについて実際に LCS を求めることでこの問題を \(O(|s||t|)\) で解くことができます。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

int main(){
  string sss, ttt;
  int k;
  cin >> sss >> ttt >> k;
  
  int n = sss.size(), m = ttt.size();
  vector<int> ss, tt;
  for(int i=0; i<n; i++){
    ss.push_back(sss[i] - '0');
  }
  for(int i=0; i<m; i++){
    tt.push_back(ttt[i] - '0');
  }
  
  auto lcs=[](vector<int> s, vector<int> t){
    int n=s.size();
    int m=t.size();
    vector<vector<int>>dp(n+1,vector<int>(m+1));
    for(int i=0; i<n; i++){
      for(int j=0; j<m; j++){
        dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j+1]);
        dp[i+1][j+1] = max(dp[i+1][j+1], dp[i+1][j]);
        if(s[i] == t[j]){
          dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j]+1);
        }
      }
    }
    return dp[n][m];
  };
  
  int ans = 0;
  for(int s1=0; s1<2; s1++){
    for(int s2=0; s2<2; s2++){
      for(int t1=0; t1<2; t1++){
        for(int t2=0; t2<2; t2++){
          if(s1 + s2 + t1 + t2 > k){
            continue;
          }
          vector<int> s = ss, t = tt;
          if(s1 && (s.size()==1 || s[0]==s[1])){
            s[0] ^= 1;
          }
          if(s2 && (s.size()==1 || s[n-1]==s[n-2])){
            s[n-1] ^= 1;
          }
          if(t1 && (t.size()==1 || t[0]==t[1])){
            t[0] ^= 1;
          }
          if(t2 && (t.size()==1 || t[m-1]==t[m-2])){
            t[m-1] ^= 1;
          }
          ans = max(ans, lcs(s, t));
        }
      }
    }
  }
  
  cout << ans << endl;
}

実装例 (Python)

SS = list(map(int, input()))
TT = list(map(int, input()))
K = int(input())

def lcs(S, T):
  N = len(S)
  M = len(T)
  dp = [[0]*(M+1) for _ in range(N+1)]
  for i in range(N):
    for j in range(M):
      dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j+1])
      dp[i+1][j+1] = max(dp[i+1][j+1], dp[i+1][j])
      if S[i] == T[j]:
        dp[i+1][j+1] = max(dp[i+1][j+1], dp[i][j]+1)
  return dp[N][M]

ans = 0
for s1 in range(2):
  for s2 in range(2):
    for t1 in range(2):
      for t2 in range(2):
        if s1 + s2 + t1 + t2 > K:
          continue
        S = list(SS)
        T = list(TT)
        if s1 and (len(S)==1 or S[0]==S[1]):
          S[0] ^= 1
        if s2 and (len(S)==1 or S[-1]==S[-2]):
          S[-1] ^= 1
        if t1 and (len(T)==1 or T[0]==T[1]):
          T[0] ^= 1
        if t2 and (len(T)==1 or T[-1]==T[-2]):
          T[-1] ^= 1
        ans = max(ans, lcs(S, T))

print(ans)

posted:
last update: