2257-Sakura Poetry
解法
解説通りのDP
AOJで通すにはmapを用いてメモリ利用量を減らす必要がある.
実装(C++)
メモリ管理がダメダメです.
#include <queue> #include <iostream> #include <algorithm> #include <string> #include <cstring> #include <map> using namespace std; #define REP(i,x) for(int i=0;i<(int)x;i++) #define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++) struct PMA{ PMA* next[256]; //失敗時に0を利用 int matched; int v; //Debug PMA(){REP(i,256)next[i]=0;matched=false;} ~PMA(){REP(i,256)if(next[i])delete next[i];} }; PMA* pmas[5000]; int pma_count=1; //パターンマッチングオートマトンの生成.生成元パターンをpattern,個数をcountに代入して用いる PMA *buildPMA(string pattern[],int count){ PMA *root=new PMA,*now; root->next[0]=root; root->v=0; REP(i,count){ now=root; for(int j=0;j<(int)pattern[i].size();j++){ if(now->next[(int)pattern[i][j]]==0){ now->next[(int)pattern[i][j]]=new PMA; now->next[(int)pattern[i][j]]->v=pma_count; pmas[pma_count++]=now->next[(int)pattern[i][j]]; } now=now->next[(int)pattern[i][j]]; } now->matched+=1; } queue<PMA*> que; for(int i=1;i<256;i++){ if(!root->next[i])root->next[i]=root; //使われていない部分のnextをrootに else{ root->next[i]->next[0] = root; //失敗時はルートに戻る que.push(root->next[i]); } } while(!que.empty()){ now=que.front();que.pop(); for(int i=1;i<256;i++){ if(now->next[i]){ PMA *next=now->next[0]; while(!next->next[i])next=next->next[0]; now->next[i]->next[0]=next->next[i]; now->next[i]->matched+=(next->next[i]->matched); que.push(now->next[i]); } } } return root; } int match(PMA* &pma,const string &a){ int res=0; FOR(it,a){ int c=*it; while(!pma->next[c]){ pma=pma->next[0]; } pma=pma->next[c]; res+=pma->matched; } return res; } int n,m,k; string seasonword[30]; vector<string> words; int wc; vector<int> G[1000]; int fromstring(string &a){ int k=find(words.begin(),words.end(),a)-words.begin(); if(k==(int)words.size()){ words.push_back(a);wc++; } return k; } const int MOD=1000000007; //長さ.えいほこらしっく,さいごのたんご,きごのかず struct State{ int aho; int lastword; int count; }; bool operator<(const State &a,const State &b){ return a.aho==b.aho?a.lastword==b.lastword?a.count<b.count:a.lastword<b.lastword:a.aho<b.aho; } map<State,int> dp[30]; int main(){ for(;cin>>n>>m>>k;){ if(!(n|m|k))break; wc=0;words.clear(); REP(i,900)G[i].clear(); REP(i,n){ string a,b; cin>>a>>b; int a_=fromstring(a),b_=fromstring(b); G[a_].push_back(b_); } REP(i,k) cin>>seasonword[i]; pma_count=1; pmas[0]=buildPMA(seasonword,k); REP(i,30)dp[i].clear(); swap(n,m); REP(i,wc){ PMA *next=pmas[0]; int MA=match(next,words[i]); if(MA<2)dp[words[i].size()][(State){next->v,i,MA}]=1; } REP(i,n){ dp[(i+25)%30].clear(); FOR(it,dp[i%30]){ REP(q,G[it->first.lastword].size()){ int n_k=G[it->first.lastword][q]; if(i+(int)words[n_k].size()>n)continue; PMA *next=pmas[it->first.aho]; int MA=it->first.count+match(next,words[n_k]); if(MA<2){ dp[(i+words[n_k].size())%30][(State){next->v,n_k,MA}]+=it->second; dp[(i+words[n_k].size())%30][(State){next->v,n_k,MA}]%=MOD; } } } } int res=0; FOR(it,dp[n%30]){ if(it->first.count==1){ res+=it->second; res%=MOD; } } cout<<res<<endl; } return 0; }