[海军国际项目办公室]游戏
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]游戏相关的知识,希望对你有一定的参考价值。
游戏
题目描述
题解
我们可以考虑转化到后缀数组上来。
我们将串
A
A
A与串
B
B
B接在一起,将所有后缀按照字典序进行排序。
很明显,对于两个
L
C
P
LCP
LCP为
d
d
d的串
A
,
B
A,B
A,B(这里指原串的某个后缀),当我们的
K
⩽
d
K\\leqslant d
K⩽d时,这两者从串
A
A
A的起始点与串
B
B
B的起始点开始的长度为
d
d
d的子串是相等的。
而当
K
>
d
K>d
K>d时,我们可以根据其前后位置判断它们之间的大小关系。
但我们的答案要求的是使得
A
<
B
A<B
A<B,
A
=
B
A=B
A=B和
A
>
B
A>B
A>B的串的总数,我们考虑如何对其维护。
显然,我们的
K
K
K是不断增加的,在此过程中,会不断有一些
(
A
,
B
)
(A,B)
(A,B)从相等变成存在大小关系,以及还有不断有后缀由于长度不够了而不产生贡献,我们只需要对着两种情况进行维护。
显然,这是可以通过线段树进行维护的。
对于
L
C
P
LCP
LCP变得小于
K
K
K的情况,假设排序后第
i
i
i个与第
i
−
1
i-1
i−1个之间的
L
C
P
LCP
LCP为
h
i
h_{i}
hi。
那么显然,当
K
K
K变得大于
h
i
h_{i}
hi后,
i
i
i所在的还未被分开的块中,前部分与后部分会彻底分开,产生前面小于后面的贡献。
后面的
A
A
A串的失败答案中会加上前面的
B
B
B串数量,同样,前面
A
A
A的胜利答案中也会加上后面
B
B
B串的数量,也就是个区间修改。
而当一个
A
A
A串或
B
B
B串的长度不够时,它当然不可能继续产生贡献了,所以我们还得把它所做的贡献从线段树删去,也就是个单点修改。
所以事实上排序后打个线段树就行了 ,根本用不到题解所谓的矩阵。
时间复杂度
O
(
n
log
n
)
O\\left(n\\log\\,n\\right)
O(nlogn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define MAXN 400005
#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 LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,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){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'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,x[MAXN],y[MAXN],z[MAXN],c[MAXN];
int sa[MAXN],rk[MAXN],hei[MAXN],lena,lenb;
char astr[MAXN],bstr[MAXN],str[MAXN];
set<int>s;
set<int>::iterator it;
vector<int>vec[MAXN];
void getSa(){
for(int i=1;i<=n;i++)c[x[i]=str[i]]++;
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>0;i--)sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int num=0;for(int i=n-k+1;i<=n;i++)y[++num]=i;
for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)c[x[i]]++,z[i]=x[i];
for(int i=2;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>0;i--)sa[c[x[y[i]]]--]=y[i];
for(int i=1;i<=n;i++)x[i]=y[i]=0;x[sa[1]]=1;num=1;
for(int i=2;i<=n;i++)x[sa[i]]=(z[sa[i]]==z[sa[i-1]]&&z[sa[i]+k]==z[sa[i-1]+k])?num:++num;
if(num==n)break;m=num;
}
}
void getHi(){
int k=0;for(int i=1;i<=n;i++)rk[sa[i]]=i;
for(int i=1;i<=n;i++){
if(k)k--;int j=sa[rk[i]-1];
while(str[i+k]==str[j+k])k++;hei[rk[i]]=k;
}
}
class SegmentTree{
private:
LL sum1[MAXN<<2],sum2[MAXN<<2],lzy1[MAXN<<2],lzy2[MAXN<<2];
int siz[MAXN<<2],cnt[MAXN<<2];
void pushup(int rt){
sum1[rt]=sum1[lson]+sum1[rson];
sum2[rt]=sum2[lson]+sum2[rson];
siz[rt]=siz[lson]+siz[rson];
cnt[rt]=cnt[lson]+cnt[rson];
}
void pushdown(int rt){
if(lzy1[rt]){
sum1[lson]+=1ll*siz[lson]*lzy1[rt];lzy1[lson]+=lzy1[rt];
sum1[rson]+=1ll*siz[rson]*lzy1[rt];lzy1[rson]+=lzy1[rt];
lzy1[rt]=0;
}
if(lzy2[rt]){
sum2[lson]+=1ll*siz[lson]*lzy2[rt];lzy2[lson]+=lzy2[rt];
sum2[rson]+=1ll*siz[rson]*lzy2[rt];lzy2[rson]+=lzy2[rt];
lzy2[rt]=0;
}
}
public:
void build(int rt,int l,int r){
if(l==r){siz[rt]=(sa[l]<=lena);cnt[rt]=(sa[l]>lena+1);return ;}
int mid=l+r>>1;build(lson,l,mid);build(rson,mid+1,r);pushup(rt);
}
int queryCnt(int rt,int l,int r,int al,int ar){
if(l>ar||r<al||al>ar||l>r)return 0;
if(al<=l&&r<=ar)return cnt[rt];
int mid=l+r>>1,res=0;pushdown(rt);
if(al<=mid)res+=queryCnt(lson,l,mid,al,ar);
if(ar>mid)res+=queryCnt(rson,mid+1,r,al,ar)[海军国际项目办公室]矩阵