[BZOJ 3942 ]KMP+栈  [BZOJ3940]AC自动机+栈

BZOJ3942
 分析:一个个匹配,不过中途记录一下当前的fail, 这样的话删除一部分,也可以回溯到那时的状态

 
/***********************************************
Author        :lzs
Created Time  :2018年10月23日 星期二 20时08分00秒
File Name     :bzoj_3942.cpp
************************************************/
 
#include <bits/stdc++.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <math.h>
#include <stack>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define rep(i, l, r) for(int i = l; i < r; i++)
#define per(i, r, l) for(int i = r; i >= l; i--)
#define dbgln(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<"\n"
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"
 
 
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
 
const int N = (int) 1e6 + 11;
const int M = (int) 1e6 + 11;
const int MOD = (int) 1e9 + 7;
const int INF = (int) 0x3f3f3f3f;
const ll INFF = (ll) 0x3f3f3f3f3f3f3f3f;
/*-----------------------------------------------------------*/
 
char s[N], t[N];
int nxt[N];
void getnxt(char *s){
    int i, j;
    j = nxt[0] = -1;
    i = 0; int n = strlen(s);
    while(i < n){
        while(j != -1 && s[i] != s[j]) j = nxt[j];
        ++j; ++i;
        if(s[j] == s[i]) nxt[i] = nxt[j];
        else nxt[i] = j;
    }
}
int fail[N], top;
char ans[N];
int main(){
    scanf("%s%s", s, t);
    stack<char>st;
    getnxt(t);
    int j = 0; int lent = strlen(t);
    for(int i = 0; s[i]; ){
        ans[++top] = s[i];
        while(j != -1 && t[j] != s[i]) j = nxt[j];
        ++j; ++i; 
        fail[top] = j; 
        if(j == lent) {
            top -= lent;
            j = fail[top]; 
        }
    }
    for(int i = 1; i <= top; i++) putchar(ans[i]);putchar('\n');
    return 0;
}

BZOJ3940
和上一道思路一样,匹配中途维护一下当前的fail值,这样删除后,才可以回溯到原来的状态
一个模式串用kmp就可以,但是多个模式串肯定要用ac自动机了

#include<bits/stdc++.h>
using namespace std;
const int N = (int)1e5 + 11;
queue<int>q;
struct AC_{
	// 字典树相关,分别表示: 存储图,标记单词尾,总节点个数
	int c[N][26], val[N], cnt;
	int len[N];	
	int fail[N]; // 失配转移 
	int f[N];
	char ans[N]; int top;
	void ins(char *s){
		int le=strlen(s);int now=0;
		for(int i=0;i<le;i++){
			int v=s[i]-'a';
			if(!c[now][v])c[now][v]=++cnt;
			now=c[now][v];
		}
		val[now]++; //标记 是一个单词尾
		len[now] = le;
	}
	void build(){ // fail的建立, 注意fail建立之后 字典树中的指向已经变了
		// 和根节点相连的加入队列中
		for(int i=0;i<26;i++) if(c[0][i])fail[c[0][i]]=0,q.push(c[0][i]);
		while(!q.empty()){
			int u=q.front();q.pop();
			for(int i=0;i<26;i++)
				if(c[u][i]) fail[c[u][i]]=c[fail[u]][i],q.push(c[u][i]);//如果u有i这个分支
				else c[u][i]=c[fail[u]][i]; // 可以跳很多
		}
	}
	void query(char *s){
		int le=strlen(s);
		int now=0;
		for(int i=0;i<le;i++){
			ans[++top] = s[i];
			now=c[now][s[i]-'a'];
			// val[t] = -1 表示已经访问过, t = 0表示到了根节点
			f[top] = now;
			if(val[now]){ //核心!因为模式串之间不会有互为子串,所以不用沿着fail下找
				// 这样才不会TLE
				top -= len[now];
				now = f[top];	
				continue;
			}		
		}
		for(int i = 1; i <= top; i++) putchar(ans[i]);putchar('\n');
	}
}AC;
int n;char p[1000005];
char s[N];
int main(){
	scanf("%s", p);
	int n; scanf("%d" ,&n);
	for(int i = 0; i < n; i++){
		scanf("%s", s);
		AC.ins(s);
	}
	AC.build();
	AC.query(p);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一道经典的单调问题。题目描述如下: 有 $n$ 个湖,第 $i$ 个湖有一个高度 $h_i$。现在要在这些湖之间挖一些沟渠,使得相邻的湖之间的高度差不超过 $d$。请问最少需要挖多少个沟渠。 这是一道单调的典型应用题。我们可以从左到右遍历湖的高度,同时使用一个单调来维护之前所有湖的高度。具体来说,我们维护一个单调递增的中存储的是湖的下标。假设当前遍历到第 $i$ 个湖,我们需要在之前的湖中找到一个高度最接近 $h_i$ 且高度不超过 $h_i-d$ 的湖,然后从这个湖到第 $i$ 个湖之间挖一条沟渠。具体的实现可以参考下面的代码: ```c++ #include <cstdio> #include <stack> using namespace std; const int N = 100010; int n, d; int h[N]; stack<int> stk; int main() { scanf("%d%d", &n, &d); for (int i = 1; i <= n; i++) scanf("%d", &h[i]); int ans = 0; for (int i = 1; i <= n; i++) { while (!stk.empty() && h[stk.top()] <= h[i] - d) stk.pop(); if (!stk.empty()) ans++; stk.push(i); } printf("%d\n", ans); return 0; } ``` 这里的关键在于,当我们遍历到第 $i$ 个湖时,所有比 $h_i-d$ 小的湖都可以被舍弃,因为它们不可能成为第 $i$ 个湖的前驱。因此,我们可以不断地从顶弹出比 $h_i-d$ 小的湖,直到顶的湖高度大于 $h_i-d$,然后将 $i$ 入。这样,中存储的就是当前 $h_i$ 左边所有高度不超过 $h_i-d$ 的湖,顶元素就是最靠近 $h_i$ 且高度不超过 $h_i-d$ 的湖。如果不为空,说明找到了一个前驱湖,答案加一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值