54 D Writing a Song

問題

長さnの歌を次の条件を満たすように作りたい。
文字列でPが与えられる。

  • そのPが、指定された位置には出現し、指定されていない位置には出現しない。
  • アルファベットの最初からk種類(以下)のみからなる

出現の指定は01からなる文字列により行われる。
i番目が0ならば、歌のi文字目からはPではない文字列が始まり、
1ならばPが始まる。

制約条件

n,m≦100
k≦26

方針

PMA(パターンマッチオートマトン)を作る。


すると、dp[pos][state]を、
歌をpos文字作って、そのときのオートマトンの状態がstateであるような状態にたどりつけるかどうかとするDPが出来る。


DPの経路復元をしてやることにより歌が出力できる。

ソースコード

int *buildFail(char *p) {
  int m = strlen(p);
  int *fail = new int[m+1];
  int j = fail[0] = -1;
  for (int i = 1; i <= m; ++i) {
    while (j >= 0 && p[j] != p[i-1]) j = fail[j];
    fail[i] = ++j;
  }
  return fail;
}
int n,k, *pma;
char in[101],oc[101];
int prev[101][101],c[101][101];
bool dp[101][101];

void run(){
  cin>>n>>k;
  cin>>in>>oc;
  pma=buildFail(in);
  
  memset(dp,0,sizeof(dp)); dp[0][0]=1;
  int m=strlen(in),l=strlen(oc);
  rep(i,n)rep(j,m)if(dp[i][j]){
    rep(p,k){
      int s=j;
      while(s>=0&&in[s]-'a'!=p)s=pma[s];
      if(++s>=m){
        s=pma[s];
        if(i+1<m||oc[i-m+1]=='1'){
          dp[i+1][s]=1;
          c[i+1][s]=p; prev[i+1][s]=j;
        }
      }
      else{
        if(i+1<m||oc[i-m+1]=='0'){
          dp[i+1][s]=1;
          c[i+1][s]=p; prev[i+1][s]=j;
        }
      }
    }
  }
  rep(i,m+1)if(dp[n][i]){
    string ans;
    for(int s=i,j=n;j;j--)ans.pb(c[j][s]+'a'), s=prev[j][s];
    reverse(all(ans));
    cout<<ans<<endl; return;
  }
  cout<<"No solution"<<endl;
}