TopCoder SRM 519 Div1 Medium RequiredSubstrings

問題

n個の文字列が与えられる。
このうちちょうどC個をその部分文字列として含むような、長さLの文字列の個数を求めよ。

制約条件

n≦6
L≦50

方針

まず、Aho-Corasickでパターンマッチオートマトンを作る。
オートマトンのどの状態にいるか、文字列のうちどれにマッチしたか、長さをキーにしてDPする。
状態遷移はa〜zのアルファベット。


DPの部分が計算量で支配的なので、パターンマッチオートマトンの作成はナイーブにやっても通るらしい。


状態数は50*2^6*50*6くらいで、遷移が26なので計算量的にかなり結構余裕のはず。
なんだけど、最悪で180msとかかかっていてびびる。
mapでlogがかかってるのが遅いのかも。

ソースコード

struct PMA {
  PMA *next[0x100]; // next[0] is for fail
  vector<int> accept;
  PMA() { fill(next, next+0x100, (PMA*)0); }
};
PMA *buildPMA(char p[10][51], int size) {
  PMA *root = new PMA;
  for (int i = 0; i < size; ++i) { // make trie
    PMA *t = root;
    for (int j = 0; p[i][j]; ++j) {
      char c = p[i][j];
      if (t->next[c] == NULL) t->next[c] = new PMA;
      t = t->next[c];
    }
    t->accept.push_back(i);
  }
  queue<PMA*> Q; // make failure link using bfs
  for (int c = 'a'; c <= 'z'; ++c) {
    if (root->next[c]) {
      root->next[c]->next[0] = root;
      Q.push(root->next[c]);
    } else root->next[c] = root;
  }
  while (!Q.empty()) {
    PMA *t = Q.front(); Q.pop();
    for (int c = 'a'; c <= 'z'; ++c) {
      if (t->next[c]) {
        Q.push(t->next[c]);
        PMA *r = t->next[0];
        while (!r->next[c]) r = r->next[0];
        t->next[c]->next[0] = r->next[c];
      	fr(i,r->next[c]->accept)t->next[c]->accept.pb(*i);
      }
    }
  }
  return root;
}
const int mod=9+(int)1e9;
char str[10][51];
int n;
map<pair<int,PMA*>,int > dp[51];

class RequiredSubstrings {
	public:
	int solve(vector <string> words, int C, int L) 
	{
		n=words.size();
		rep(i,n)sprintf(str[i],"%s",words[i].c_str());
		PMA *pma=buildPMA(str,n);
		
		
		rep(i,51)dp[i].clear();
		dp[0][mp(0,pma)]=1;
		rep(i,L)fr(j,dp[i]){
			for(char c='a';c<='z';c++){
				PMA *v=j->first.second;
				int flag=j->first.first;
				while(!v->next[c])v=v->next[0];
				v=v->next[c];
				rep(k,v->accept.size())flag|=1<<v->accept[k];
				(dp[i+1][mp(flag,v)]+=j->second)%=mod;
			}
		}
		
		int ans=0;
		fr(i,dp[L])if(__builtin_popcount(i->first.first)==C)
			(ans+=i->second)%=mod;
		return ans;
	}
};