Official

D - String Bags Editorial by en_translator


To come straight to the point, this problem can be solved with dynamic programming (DP).

Let \(dp[\) how many bags were processed? \(][\) how long is the prefix of \(T\) that matched? \(] = \) { minimum money required }.

Consider concatenating a string \(X\) in the \((i+1)\)-th bag to the end of \(S\). Then, transition from \(dp[i][|S|]\) to \(dp[i+1][|S|+|X|]\) is possible only if the \((|S|+1)\)-th through \((|S|+|X|)\)-th characters coincide with \(X\).

Under the constraint of this problem, we can naively check this condition.

Also, not choosing a string corresponds to the transition from \(dp[i][j]\) to \(dp[i+1][j]\).

By implementing this DP, the problem can be solved in about \(O(NM|S||T|)\) time (where \(M\) is the number of strings in a bag).

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;

int dp[105][105];

int main(){
  for(int i=0;i<105;i++){
    for(int j=0;j<105;j++){
      dp[i][j]=1e9;
    }
  }
  dp[0][0]=0;

  string t;
  cin >> t;
  int tl=t.size();
  int n;
  cin >> n;
  for(int i=0;i<n;i++){
    for(int j=0;j<105;j++){dp[i+1][j]=dp[i][j];}
    int m;
    cin >> m;
    while(m>0){
      m--;
      string s;
      cin >> s;
      int sl=s.size();
      for(int j=0;j+sl<=tl;j++){
        bool ok=true;
        for(int k=0;k<sl;k++){
          if(t[j+k]!=s[k]){ok=false;break;}
        }

        if(ok){
          dp[i+1][j+sl]=min(dp[i+1][j+sl],dp[i][j]+1);
        }
      }
    }
  }

  if(dp[n][tl]>5e8){dp[n][tl]=-1;}
  cout << dp[n][tl] << "\n";
  return 0;
}

posted:
last update: