Hatena::Grouptopcoder

kojingharangの日記 RSSフィード

 | 

2012-03-26

codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence

20:30 |  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記 を含むブックマーク はてなブックマーク -  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記  codeforces  VK Cup 2012 Round 2 (Unofficial Div. 2 Edition) 169 C. Substring and Subsequence - kojingharangの日記 のブックマークコメント

文字列sのsubstringと文字列tのsubsequenceが一致するようなものの個数を求める問題。長さはどちらも5000以内。

あとでできてる人のコードや解説を見て。

dp[i][j] = s[i]で終わるsubstringとt[j]以前の文字列のsubsequenceのうち内容が一致するものの個数

とすると、dp[i][j]はt[j]以前のsubsequenceのうちt[j]を使う場合と使わない場合に分けて考えることができる。

t[j]を使わない場合、使わないということはt[j-1]以前の文字列に対するsubsequenceなのでdp[i][j-1]を加算

t[j]を使う場合、s[i]とt[j]を両方使うことになる。

s[i]!=t[j]のときは前に何がきても一致しないので加算なし

s[i]==t[j]のときは s[i-1] でおわるsubstringとt[j-1]以前のsubsequenceが一致すればよいのでdp[i-1][j-1]、

それに加えてs[i]とt[j]一文字だけの場合があるのでさらに1を加算。

というわけで式は

dp[i][j] = dp[i][j-1] + (s[i]==t[j] ? 1+dp[i-1][j-1] : 0)

となる

答えはsubstringが終わるすべての位置について足せばいいのでΣi dp[i][t.size-1]

.....と、言われると納得するけど思いつかんのだなぁ。

本番中はs[i]以前のsubstringとt[j]以前のsubsequenceでずっと考えてて、なんか4通りあるしさらに重複してそうとなってできなかった。

しばらく考えてできないときは状態をもっと分割してみて最後に足す、というアプローチが使えるかも。

(↓あとで通したやつ)

#define MOD 1000000007LL

int main() {
	string A,B;
	cin>>A>>B;
	
	VVI dp(A.size()+1, VI(B.size()+1, 0));
	
	for(int i=1; i<A.size()+1; i++) for(int j=1; j<B.size()+1; j++) {
		dp[i][j] = ((ll)dp[i][j-1] + (A[i-1]==B[j-1] ? 1+dp[i-1][j-1]:0)) % MOD;
	}
	ll ans = 0;
	REP(i, A.size()+1) ans = (ans+dp[i][B.size()])%MOD;
	cout<<ans<<endl;
	
	return 0;
}

 |