AOJ1291 Search of Concatenated Strings
問題
文字列の列 $e_1, \cdots , e_n $ と長い文字列 $t$ が与えられる. $e_i$ の全てを $1$ つづ任意の順に結合した文字列は $t$ の部分文字列として何通り含まれるか.
方針
「$dp(i,j) = t$ の $i$ 番目までにビットで表現した集合 $j$ を全て使った文字列が一致している」 とおき,埋めていった. 一致判定を string.substr とか適当にやると TLE するのでローリングハッシュを使った. ロリハを使わなくても AC されている人がいるので理解したい.
実装
bool dp[6000][1<<13];
ll const B = 3;
ull p[6000], thash[6000];
ull shash[13];
int n,m;
int len;
char t[6000];
char ss[13][22];
int sslen[13];
int solve(){
rep(i,n){
ull x = 0;
for(int j=0;ss[i][j];j++){
x = x*B + ss[i][j];
}
shash[i] = x;
}
p[0] = 1;
thash[0] = 0;
rep(i,len){
p[i+1] = p[i]*B;
thash[i+1] = thash[i]*B + t[i];
}
rep(i,len+1)rep(j,1<<n) dp[i][j] = false;
rep(i,len+1) dp[i][0] = true;
rep(pos,len){
rep(mask,1<<n){
if(!dp[pos][mask]) continue;
rep(i,n){
if(mask>>i&1) continue;
if(pos+sslen[i] > len) continue;
ull h1 = shash[i];
ull h2 = thash[pos+sslen[i]] - thash[pos] * p[sslen[i]];
// if(h1 != h2) continue;
dp[pos+sslen[i]][mask|1<<i] |= h1 == h2; // t.substr(pos,ss[i].size()) == ss[i];
}
}
}
int ans = 0;
rep(i,len+1){
if(dp[i][(1<<n)-1]){
++ans;
}
}
return ans;
}
signed main(){
while(scanf("%d%d",&n,&m), n){
len = 0;
rep(i,n){
scanf("%s",ss[i]);
sslen[i] = strlen(ss[i]);
}
rep(i,m){
static char buf[22];
scanf("%s",buf);
int l = strlen(buf);
rep(i,l) t[i+len] = buf[i];
len += l;
}
cout << solve() << endl;
}
}