国庆集训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_ildots 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;
}
原文地址:https://www.cnblogs.com/dream1024/p/15522937.html