國慶集訓Day1T1撰寫部落格
阿新 • • 發佈:2021-11-08
目錄
國慶集訓Day1T1撰寫部落格
):
,最終\(j\)的下屆(\(boundary\))都是確定的,且是遞增的,且狀態轉移方程中每一項都只和\(i,j\)中的一個有關,符合單調佇列優化條件.
題目
http://noip.ybtoj.com.cn/contest/584/problem/1
給定長度為\(n\)的字串\(s\)和\(m\)個字串\(t\),將\(s\)中的第\(i\)個字元替換成空格的代價為\(a_i\),求使\(s\)中不出現任何一個\(t\)的最小代價.
思路
設\(f_i\)表示處理完\(s\)的前\(i\)個字元的最小代價.
則有\(f_0=0\).
轉移(\(pre_i\)表示存在字串\(t\) ,\(t\)和 \(s\)的字串\(s_{pre_i\ldots i}\)相等,且\(pre_i\)最小,若不存在,\(pre_i=0\)
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for (int i = 1; i <= n; i++) {
int boundary = pre[i];
for (int j = i; j >= boundary; j--) {
boundary = max(boundary, pre[j]);
f[i] = min(f[i], f[j - 1] + val[j]);
}
}
cout << f[n];
注意到對於每一個\(i\)
故單調佇列優化後可以做到\(O(n)\).
程式碼
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef unsigned long long ull; const int N = 2e5 + 10 , M = 15; const ull mod1 = 1e9 + 7 , base1 = 1331; const ull mod2 = 1e6 + 7 , base2 = 131; int read() { int re = 0; char c = getchar(); while(c < '0' || c > '9')c = getchar(); while(c >= '0' && c <= '9')re = (re << 1) + (re << 3) + c - '0' , c =getchar(); return re; } char readc() { char c = getchar(); while(c < 'a' || c > 'z')c = getchar(); return c; } int n , m; int val[N]; int pre[N]; int f[N]; struct MQueue { int head , tail; int j[N] , f[N]; void pop(int boundary) { while(head < tail && j[head] < boundary)++head; } void push(int j_ , int f_) { while(head < tail && f[tail - 1] >= f_)--tail; j[tail] = j_ , f[tail] = f_; ++tail; } int front() { return head == tail ? 1e9 : f[head]; } } mQue; namespace input { char s[N] , t[15][N]; int len[15]; template <ull base , ull mod> ull GetValue (int l , int r) { static ull p[N] , val[N] ; static bool vis = false; if(!vis) { vis = true; p[0] = 1; for(int i = 1 ; i <= n ; i++) p[i] = p[i - 1] * base % mod , val[i] = val[i - 1] * base % mod + s[i] ; } return (val[r] - val[l - 1] * p[r - l + 1] % mod + mod) % mod; } void input() { n = read() , m = read(); for(int i = 1 ; i <= n ; i++)s[i] = readc(); for(int i = 1 ; i <= n ; i++)val[i] = read(); for(int i = 1 ; i <= m ; i++) { ull v1 = 0 , v2 = 0; t[i][len[i] = 1] = readc(); do t[i][++len[i]] = getchar(); while(t[i][len[i]] >= 'a' && t[i][len[i]] <= 'z'); --len[i]; for(int j = 1 ; j <= len[i] ; j++) v1 = (v1 * base1 + t[i][j]) % mod1 , v2 = (v2 * base2 + t[i][j]) % mod2; for(int j = 1 ; j + len[i] - 1 <= n ; j++) if(v1 == GetValue<base1 , mod1>(j , j + len[i] - 1) && v2 == GetValue<base2 , mod2>(j , j + len[i] - 1)) pre[j + len[i] - 1] = max(pre[j + len[i] - 1] , j); } } } int main() { freopen("wzadx.in" , "r" , stdin); freopen("wzadx.out" ,"w" , stdout); input::input(); memset(f , 0x3f , sizeof(f)); f[0] = 0 , mQue.push(0 , f[0]); int boundary = 0; for(int i = 1 ; i <= n ; i++) { boundary = max(pre[i] , boundary); mQue.push(i , f[i - 1] + val[i]); mQue.pop(boundary); f[i] = min(f[i] , mQue.front()); } cout << f[n]; return 0; }