[BZOJ2384/Ceoi2011]Match

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ2384/Ceoi2011]Match相关的知识,希望对你有一定的参考价值。

Match

题解

字符串题,一看就是hash嘛,不会有人去想kmp吧

我们可以考虑表示出序列 B B B,其中 b i b_{i} bi表示第 i i i小的数再子串中的位置。
怎么表示一个序列呢, h a s h hash hash就行了呗。
所以我们要找到排列 a a a h a s h hash hash值与序列 b b b中每个位置开始的子串的 h a s h hash hash值相等即可。

如何维护序列 b b b的子串的 h a s h hash hash值呢,我们可以考虑扫描线加平衡树来进行维护。
平衡树就维护我们的 B B B序列。
每次从 i i i i + 1 i+1 i+1维护我们会需要将 i i i B B B中删除再将 i + n i+n i+n加入。
删除点 i i i直接去掉值为 i i i所在的节点,也就是值为 1 1 1的节点,再将 B B B全局减一。
而插入点 i + n i+n i+n,我们只需要知道 [ i , i + n ) [i,i+n) [i,i+n)中有多少个数比 b i + n b_{i+n} bi+n小,将平衡树从那个地方裂开加入 b n b_{n} bn即可。
比它小的值的个数我们可以靠v了采用树状数组进行维护。
由于我们维护的是 h a s h hash hash值,我们同样需要将我们的序列 B B B转化成一个值,我们设我们转化的值 x = ∑ i = 1 n ( n + 1 ) i − 1 B i x=\\sum_{i=1}^{n}(n+1)^{i-1}B_{i} x=i=1n(n+1)i1Bi
懒标记下传的减一我们明显只需要减去 ∑ i = 0 s i z − 1 ( n + 1 ) i \\sum_{i=0}^{siz-1}(n+1)^i i=0siz1(n+1)i,这是可以预处理出来的,而单个点的插入也只会改变一条链,我们们只需要合并时用下面的方法合并:
s u m i = s u m l s o n + ( n + 1 ) s i z l s o n v a l i + ( n + 1 ) s i z l s o n + 1 v a l r s o n sum_{i}=sum_{lson}+(n+1)^{siz_{lson}}val_{i}+(n+1)^{siz_{lson+1}}val_{rson} sumi=sumlson+(n+1)sizlsonvali+(n+1)sizlson+1valrson
每次比较当前的 h a s h hash hash值与我们目标序列的 h a s h hash hash值是否相同即可。

上面方法明显复杂度时 O ( n log ⁡   n ) O\\left(n\\log\\,n\\right) O(nlogn),但实测会 T T T, 都怪这**出题人卡常, 考虑优化。
平衡树不行我们还可以用值域线段树,我们只需要将区间的 s i z siz siz改为该区间中有值的点的个数,合并时将左区间的 s i z siz siz做次方项乘带右区间上即可。

时间复杂度依然是 O ( n l o g   n ) O\\left(nlog\\,n\\right) O(nlogn),但实际上快了一倍多。

源码

然而线段树会被 64 M B 64MB 64MB卡空间,我刚好 65 M B 65MB 65MB,需要将线段树的大小设为 3 n + 5 3n+5 3n+5,可能不大严谨,大不了动态开点。

#include<bits/stdc++.h> 
using namespace std;
#define MAXN 1000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int zero=10000;
const int lim=30000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,a[MAXN],b[MAXN],c[MAXN],pown[MAXN],sump[MAXN],mban,d[MAXN];
vector<int>ans;
struct ming{
	int lzy,siz,sum;
	ming(){siz=lzy=sum=0;}
};
class SegmentTree{
	private:
		ming tr[MAXN*3+5];	
	public:
		void pushup(int rt){
			tr[rt].siz=tr[lson].siz+tr[rson].siz;
			tr[rt].sum=add(tr[lson].sum,1ll*pown[tr[lson].siz]*tr[rson].sum%mo,mo);
		}
		void pushdown(int rt){
			if(!tr[rt].lzy)return ;
			if(tr[lson].siz)tr[lson].lzy=add(tr[rt].lzy,tr[lson].lzy,mo),
				tr[lson].sum=add(tr[lson].sum,1ll*(mo-tr[rt].lzy)*sump[tr[lson].siz-1]%mo,mo);
			if(tr[rson].siz)tr[rson].lzy=add(tr[rt].lzy,tr[rson].lzy,mo),
				tr[rson].sum=add(tr[rson].sum,1ll*(mo-tr[rt].lzy)*sump[tr[rson].siz-1]%mo,mo);
			tr[rt].lzy=0;
		}
		void insert(int rt,int l,int r,int ai,int aw){
			if(l>r||l>以上是关于[BZOJ2384/Ceoi2011]Match的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2384[Ceoi2011]Match 特殊匹配条件的KMP+树状数组

[bzoj1135][Ceoi2011]Match_线段树

[BZOJ2286][SDOI2011]消耗战

BZOJ 1264 [AHOI2006]基因匹配Match

bzoj1264 [AHOI2006]基因匹配Match 树状数组+lcs

BZOJ1264[AHOI2006]基因匹配Match DP+树状数组