1. 程式人生 > 其它 >G. Anthem of Berland - kmp+DP

G. Anthem of Berland - kmp+DP

G. Anthem of Berland

https://codeforces.com/contest/808/submission/156274622

題意

給定兩個字串 s,t, s中可含有'?'問號可以由任何字母代替
將s中的所有'?'用某個字母代替後 s中最多可以匹配多少個t (可以重疊部分)

思路

用dp[i]表示s的前i個字元最多可匹配的t串的數量
用b[i]表示s的前i個位置 第i個位置與t匹配情況下的t出現的最大次數
用nx[]陣列預處理t的最大前後綴匹配長度 因為當有相同前後綴的時候可能會有重疊的t在重疊的情況下可能匹配的更多 轉移的情況就是b[i] = max(b[i], b[i - t.size() + k])了
用動態規劃 實現b陣列和dp陣列填充

#include<bits/stdc++.h>
#include<unordered_map>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-4;
const ll N = 1e6 + 5;
const int M = 1e5 + 5;
const int mod = 1e9 + 7;
ll n, m, q;
ll a[N], nx[N], dp[N], b[N];
string s, t;
//用kmp預處理nx陣列
void getnx(string s) {
	ll k = -1, j = 0;
	nx[0] = -1;
	while (j < s.size()) {
		if (k == -1 || s[k] == s[j]) {
			k++;
			j++;
			nx[j] = k;
		}
		else k = nx[k];
	}
}
//判斷當前p位置開始能否匹配一個t
bool check(ll p) {
	for (int i = p, j = 0; i < s.size() && j < t.size(); i++, j++) {
		if (s[i] != t[j] && s[i] != '?') return false;
	}
	return true;
}

void solve() {
	cin >> s >> t;
	getnx(t);
	int flag = 1, cnt = 0, cnt2 = 0, f, fg = 0;
	if (s.size() < t.size()) {
		cout << 0 << "\n";
		return;
	}
	for (int i = 0; i <= s.size() - t.size(); i++) {
                //先將前一個dp值轉移過來
		dp[i + t.size()] = dp[i + t.size() - 1];
                //判斷以p為起點能否與t匹配
		if (check(i)) {
                        //先將b[i + t.size()]賦值為dp[i]因為一定包含dp[i]的值
			b[i + t.size()] = dp[i];
                        //用nx陣列取出可轉移成b[i + t.size()]的最優情況 
			for (int k = nx[t.size()]; k >= 0; k = nx[k]) {
				b[i + t.size()] = max(b[i + t.size()], b[i + k]);
			}
                        //當前位置可匹配的再加1
			b[i + t.size()]++;
            //取與不取擇優(即是否將i開始的一串匹配成t)
            dp[i + t.size()] = max(dp[i + t.size()], b[i + t.size()]);
		}
		//cout << dp[i + 1] << " ";
	}
        //輸出
	cout << dp[s.size()] << "\n";

}

signed main()
{
	IOS;
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}

}