[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)i−1Bi。
懒标记下传的减一我们明显只需要减去
∑
i
=
0
s
i
z
−
1
(
n
+
1
)
i
\\sum_{i=0}^{siz-1}(n+1)^i
∑i=0siz−1(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+树状数组