国庆集训Day1T1撰写博客

国庆集训Day1T1撰写博客

题目

http://noip.ybtoj.com.cn/contest/584/problem/1

给定长度为\(n\)的字符串\(s\)\(m\)个字符串\(t\),将\(s\)中的第\(i\)个字符替换成空格的代价为\(a_i\),求使\(s\)中不出现任何一个\(t\)的最小代价.

image-20211108095227972

思路

\(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\),最终\(j\)的下届(\(boundary\))都是确定的,且是递增的,且状态转移方程中每一项都只和\(i,j\)中的一个有关,符合单调队列优化条件.

故单调队列优化后可以做到\(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;
}
posted @ 2021-11-08 10:07  追梦人1024  阅读(25)  评论(0编辑  收藏  举报