bzoj3796Mushroom追妹纸

题目描述

Mushroom最近看上了一个漂亮妹纸。他选择一种非常经典的手段来表达自己的心意——写情书。考虑到自己的表达能力,Mushroom决定不手写情书。他从网上找到了两篇极佳的情书,打算选择其中共同的部分。另外,Mushroom还有个一个情敌Ertanis,此人也写了封情书给妹子。
Mushroom不希望自己的情书中完整的出现了情敌的情书。(这样抄袭的事情就暴露了)。
Mushroom把两封情书分别用字符串s1和s2来表示,Ertanis的情书用字符串s3来表示,他要截取的部分用字符串w表示。
需满足:
1、w是s1的子串
2、w是s2的子串
3、s3不是w的子串
4、w的长度应尽可能大
所谓子串是指:在字符串中连续的一段。
题解
我真是有看见字符串想SAM综合征。。
要求匹配的串只有两个,可以把它们连起来求一遍SA。
然后KMP求出c在大串中出现的位置。
维护一个数组f[i]表示从i位置开始至多延长多少个位置保证不包含c。
然后扫两遍,一遍算第一个串对第二个串的贡献,再算第二个串对第一个串的贡献,滚动维护一下min(height)就好了。
又TM开小数组了。、
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200009
using namespace std;
int n,m,sa[N],rnk[N],tong[N],y[N],height[N],n1,fail[N],f[N],ans;
bool b[N],tag[N];
char s[N],s1[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);rnk[sa[]]=p=;
for(int i=;i<=n;++i)rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(s[i+j]==s[sa[rnk[i]-]+j])j++;
height[rnk[i]]=j;
}
}
inline void check(int pos,int ln){
int j=;
for(int i=pos;i<=pos+ln-;++i){
while(j&&s[i]!=s1[j+])j=fail[j];
if(s[i]==s1[j+])j++;
if(j==n1){cout<<"gan";return;}
}
cout<<"yeah";
}
int main(){
scanf("%s%s",s+,s1+);
n=strlen(s+);n1=strlen(s1+);
for(int i=;i<=n;++i)f[i]=n-i+;s[++n]='#';
for(int i=;i<=n1;++i)s[++n]=s1[i],b[n]=,f[n]=n1-i+;
SA();
scanf("%s",s1+);n1=strlen(s1+);
int j=;
for(int i=;i<=n1;++i){
while(j&&s1[i]!=s1[j+])j=fail[j];
if(s1[i]==s1[j+])j++;fail[i]=j;
}
j=;
for(int i=;i<=n;++i){
while(j&&s[i]!=s1[j+])j=fail[j];
if(s[i]==s1[j+])j++;
if(j==n1)tag[i-j+]=;
}
int xian=n+;
for(int i=n;i>=;--i){
if(tag[i])xian=min(xian,i+n1-);
f[i]=min(f[i],xian-i);
}
xian=;
for(int i=;i<=n;++i){
int pos=sa[i];
if(!b[pos])xian=min(xian,height[i]),ans=max(ans,min(f[pos],xian));
else xian=2e9;
}
xian=;
for(int i=;i<=n;++i){
int pos=sa[i];
if(b[pos])xian=min(xian,height[i]),ans=max(ans,min(f[pos],xian));
else xian=2e9;
}
cout<<ans;
return ;
}
SA四连
bzoj1692队列变换
FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”。在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席前依次走过。 今年,竞赛委员会在接受队伍报名时,采用了一种新的登记规则:他们把所有队伍中奶牛名字的首字母取出,按它们对应奶牛在队伍中的次序排成一列(比如说,如果FJ带去的奶牛依次为Bessie、Sylvia、Dora,登记人员就把这支队伍登记为BSD)。登记结束后,组委会将所有队伍的登记名称按字典序升序排列,就得到了他们的出场顺序。 FJ最近有一大堆事情,因此他不打算在这个比赛上浪费过多的时间,也就是说,他想尽可能早地出场。于是,他打算把奶牛们预先设计好的队型重新调整一下。 FJ的调整方法是这样的:每次,他在原来队列的首端或是尾端牵出一头奶牛,把她安排到新队列的尾部,然后对剩余的奶牛队列重复以上的操作,直到所有奶牛都被插到了新的队列里。这样得到的队列,就是FJ拉去登记的最终的奶牛队列。 接下来的事情就交给你了:对于给定的奶牛们的初始位置,计算出按照FJ的调整规则所可能得到的字典序最小的队列。
每次只有两种选择,从前拿和从后拿,判断这个需要字典序,用后缀数组就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 210002
using namespace std;
int n,m,rnk[N],y[N],tong[N],sa[N],top;
char s[N],zh[N],c[];
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();
swap(rnk,y);
rnk[sa[]]=p=;
for(int i=;i<=n;++i)rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;++i)scanf("%s",c),s[i]=c[];
int zu=n;
s[++n]='#';
for(int i=zu;i>=;--i)s[++n]=s[i];
SA();
int p=,q=zu+,pp=,qq=zu,cnt=;
for(int i=;i<=zu;++i){
if(rnk[p]<rnk[q]){printf("%c",s[pp]);pp++;p++;}
else{printf("%c",s[qq]);qq--;q++;}
cnt++;if(cnt==)puts(""),cnt=;
}
return ;
}

牛奶模式Milk Patterns

农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。

SA完后用单调队列维护一下长度为k的最小值就可以了。

#include<iostream>
#include<cstdio>
#define N 100002
#define M 1000002
using namespace std;
int n,m,tong[M],sa[N],rnk[N],y[N],a[N],k,h,t,q[N],height[N],ans;
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
for(int i=;i<=n;++i)rnk[i]=a[i],y[i]=i;
qsort();
for(int w=,p=;p<n;w<<=,m=p){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);rnk[sa[]]=p=;
for(int i=;i<=n;++i)rnk[sa[i]]=(y[sa[i-]]==y[sa[i]]&&y[sa[i-]+w]==y[sa[i]+w])?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(a[i+j]==a[sa[rnk[i]-]+j])j++;
height[rnk[i]]=j;
}
}
int main(){
n=rd();k=rd();k--;
for(int i=;i<=n;++i)a[i]=rd(),m=max(m,a[i]);
SA();h=;t=;
for(int i=;i<=n;++i){
while(h<=t&&q[h]<i-k+)h++;
while(h<=t&&height[i]<=height[q[t]])t--;
q[++t]=i;
if(i>=+k-)ans=max(ans,height[q[h]]);
}
cout<<ans;
return ;
}

bzoj2946[Poi2000]公共串

求n个串的最长公共子串。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 50002
using namespace std;
int n,m,tong[N],sa[N],rnk[N],y[N],height[N],ans,p[][N],len,tag[N],ji[],num;
char s[N],s1[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;w<<=,m=p){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);rnk[sa[]]=p=;
for(int i=;i<=n;++i)rnk[sa[i]]=(y[sa[i-]]==y[sa[i]]&&y[sa[i-]+w]==y[sa[i]+w])?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(s[i+j]==s[sa[rnk[i]-]+j])j++;
height[rnk[i]]=j;
p[][rnk[i]]=j;
}
for(int i=;(<<i)<=n;++i)
for(int j=;j+(<<i)-<=n;++j)p[i][j]=min(p[i-][j],p[i-][j+(<<i-)]);
}
inline int RMQ(int l,int r){
int x=log2(r-l+);
return min(p[x][l],p[x][r-(<<x)+]);
}
int main(){
num=rd();
for(int i=;i<=num;++i){
scanf("%s",s1+);len=strlen(s1+);
for(int j=;j<=len;++j)s[++n]=s1[j],tag[n]=i;s[++n]=i;
}
SA();
for(int i=;i<=n;++i){
int id=sa[i];
ji[tag[id]]=i;int nn=2e9;
for(int j=;j<=num;++j)nn=min(nn,ji[j]);
if(!nn)continue;
ans=max(ans,RMQ(nn+,i));
}
cout<<ans;
return ;
}

bzoj3230相似子串

我们可以维护一个数组sum表示前i名后缀能够产生的本质不同的子串。

然后确定第i个子串可以用二分。

求公共后缀那块可以搞一个反着的后缀数组。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 100002
#define pa pair<int,int>
#define mm make_pair
using namespace std;
typedef long long ll;
ll ans;
int n,m,tong[N],y[N],q;
inline ll rd(){
ll x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct suffixarray{
int sa[N],rnk[N],p[][N],height[N];
ll sum[N];
char s[N];
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void build(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;w<<=,m=p){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);rnk[sa[]]=p=;
for(int i=;i<=n;++i)rnk[sa[i]]=(y[sa[i-]]==y[sa[i]]&&y[sa[i-]+w]==y[sa[i]+w])?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(s[i+j]==s[sa[rnk[i]-]+j])j++;
height[rnk[i]]=j;
p[][rnk[i]]=j;
}
for(int i=;(<<i)<=n;++i)
for(int j=;j+(<<i)-<=n;++j)p[i][j]=min(p[i-][j],p[i-][j+(<<i-)]);
for(int i=;i<=n;++i)sum[i]=sum[i-]+n-sa[i]+-height[i];
}
inline pa get(ll x){
int l=,r=n;ll ans1,ans2;
if(sum[n]<x)return mm(-,-);
while(l<=r){
int mid=(l+r)>>;
if(sum[mid]>=x){ans1=mid;ans2=n-sa[mid]+-(sum[mid]-x);r=mid-;}
else l=mid+;
}
return mm(ans1,ans2);
}
inline int RMQ(int l,int r){
if(l>r)return 2e9;
int lo=log2(r-l+);
return min(p[lo][l],p[lo][r-(<<lo)+]);
}
}sa1,sa2;
int main(){
n=rd();q=rd();
scanf("%s",sa1.s+);
for(int i=;i<=n;++i)sa2.s[i]=sa1.s[n-i+];
sa1.build();sa2.build();ll x,y;
while(q--){
x=rd();y=rd();ans=;
pa xx=sa1.get(x),yy=sa1.get(y);
if(yy.first<){printf("-1\n");continue;}
ll zz=sa1.RMQ(xx.first+,yy.first);//cout<<zz<<endl;
zz=min(zz,(ll)min(yy.second,xx.second));
ans+=zz*zz;
xx.first=sa2.rnk[n-sa1.sa[xx.first]+-xx.second];
yy.first=sa2.rnk[n-sa1.sa[yy.first]+-yy.second];
zz=sa2.RMQ(min(xx.first,yy.first)+,max(yy.first,xx.first));
zz=min(zz,(ll)min(yy.second,xx.second));
ans+=zz*zz;
printf("%lld\n",ans);
}
return ;
}

POJ1743Musical Them

给一个数串,求串内有最长的子串,它出现了不止一次且存在两次出现的位置不相交。
这道题的限制条件比较多,不好直接做,考虑答案具有单调性,可以选择二分答案。

然后扫一遍height数组,把height>=mid分成若干联通块,块内维护posmin和posmax,若posmax-posmin>=mid则找到一组合法解。

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 20009
#define inf 2e9
using namespace std;
int n,m,tong[N],rnk[N],sa[N],a[N],y[N],height[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=a[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);
rnk[sa[]]=p=;
for(int i=;i<=n;++i)
rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(a[i+j]==a[sa[rnk[i]-]+j])++j;
height[rnk[i]]=j;
}
}
inline bool check(int mid){
int ma=-inf,mi=inf;
for(int i=;i<=n;++i){
if(height[i]<mid){
ma=-inf;mi=inf;
}
else{
ma=max(ma,sa[i]);mi=min(mi,sa[i]);
ma=max(ma,sa[i-]);mi=min(mi,sa[i-]);
if(ma-mi>=mid)return ;
}
}
return ;
}
int main(){
while(){
n=rd();if(!n)return ;
memset(a,,sizeof(a));
memset(rnk,,sizeof(rnk));
memset(sa,,sizeof(sa));
for(int i=;i<=n;++i)a[i]=rd();
for(int i=;i<n;++i)a[i]=a[i+]-a[i]+;a[n]=;
n--;
SA();
int l=,r=n,ans=-;
while(l<=r){
int mid=(l+r)>>;
if(check(mid))ans=mid,l=mid+;else r=mid-;
}
printf("%d\n",ans+);
}
return ;
}

POJ3145

给两个串,求这两个串大于k的公共子串数量。

这个和那道省选题(找相同字符)基本是一道题。

先求出height数组,然后维护一个单调上升的单调栈,维护一个num,一个cnt,统计答案就好了。

注意,在压栈时,压的是i-1而不是i。

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200002
using namespace std;
typedef long long ll;
int m,n,rnk[N],height[N],y[N],tong[N],tag[N],sa[N],k,n1,n2,top;
ll ans,num,st[N],cnt[N];
char s[N],s1[N],s2[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);
rnk[sa[]]=p=;
for(int i=;i<=n;++i)
rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(s[i+j]==s[sa[rnk[i]-]+j])++j;
height[rnk[i]]=j;
}
}
int main(){
while(){
k=rd();if(!k)break;
scanf("%s%s",s1+,s2+);n1=strlen(s1+);n2=strlen(s2+);
for(int i=;i<=n1;++i)s[i]=s1[i],tag[i]=;
for(int i=;i<=n2;++i)s[n1++i]=s2[i],tag[n1++i]=;s[n1+]='&';
n=n1+n2+;s[n+]=;
memset(height,,sizeof(height));
SA();
for(int i=;i<=n;++i)height[i]-=k-;ans=top=;
top=num=;
for(int i=;i<=n;++i){
int ji=tag[sa[i-]]==?:;
while(top&&st[top]>=height[i])num-=st[top]*cnt[top],ji+=cnt[top],top--;
if(height[i]>)st[++top]=height[i],cnt[top]=ji;num+=cnt[top]*st[top];
if(tag[sa[i]]==)ans+=num;
}
top=num=;
for(int i=;i<=n;++i){
int ji=tag[sa[i-]]==?:;
while(top&&st[top]>=height[i])num-=st[top]*cnt[top],ji+=cnt[top],top--;
if(height[i]>)st[++top]=height[i],cnt[top]=ji;num+=cnt[top]*st[top];
if(tag[sa[i]]==)ans+=num;
}
printf("%lld\n",ans);
}
return ;
}

bzoj3796(后缀数组)(SA四连)的更多相关文章

  1. 后缀数组(SA)总结

    后缀数组(SA)总结 这个东西鸽了好久了,今天补一下 概念 后缀数组\(SA\)是什么东西? 它是记录一个字符串每个后缀的字典序的数组 \(sa[i]\):表示排名为\(i\)的后缀是哪一个. \(r ...

  2. 后缀数组SA学习笔记

    什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...

  3. 后缀数组SA入门(史上最晦涩难懂的讲解)

    参考资料:victorique的博客(有一点锅无伤大雅,记得看评论区),$wzz$ 课件(快去$ftp$%%%),$oi-wiki$以及某个人的帮助(万分感谢!) 首先还是要说一句:我不知道为什么我这 ...

  4. [笔记]后缀数组SA

    参考资料这次是真抄的: 1.后缀数组详解 2.后缀数组-学习笔记 3.后缀数组--处理字符串的有力工具 定义 \(SA\)排名为\(i\)的后缀的位置 \(rk\)位置为\(i\)的后缀的排名 \(t ...

  5. 【字符串】后缀数组SA

    后缀数组 概念 实际上就是将一个字符串的所有后缀按照字典序排序 得到了两个数组 \(sa[i]\) 和 \(rk[i]\),其中 \(sa[i]\) 表示排名为 i 的后缀,\(rk[i]\) 表示后 ...

  6. 浅谈后缀数组SA

    这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的. 给你们分享了那么多,容我自私一回吧~ 参考资料:这位dalao的blog 一.关于求Suffix ...

  7. 后缀数组SA

    复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...

  8. 洛谷2408不同字串个数/SPOJ 694/705 (后缀数组SA)

    真是一个三倍经验好题啊. 我们来观察这个题目,首先如果直接整体计算,怕是不太好计算. 首先,我们可以将每个子串都看成一个后缀的的前缀.那我们就可以考虑一个一个后缀来计算了. 为了方便起见,我们选择按照 ...

  9. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

随机推荐

  1. Python中Celery 的基本用法以及Django 结合 Celery 的使用和实时监控进程

    celery是什么 1 celery是一个简单,灵活且可靠的,处理大量消息的分布式系统 2 专注于实时处理的异步任务队列 3 同时也支持任务调度 执行流程 Celery 基本使用 tasks.py i ...

  2. Jenkins [Error] at org.codehaus.cargo.container.tomcat.internal.AbstractTomcatManagerDeployer.redeploy(AbstractTomcatManagerDeployer.java:192)

    Deploying /root/.jenkins/workspace/zgg-crm-pre/target/crm.war to container Tomcat 7.x Remote with co ...

  3. npm5踩过的坑!

    1. 版本问题导致环境问题 我们第一次npm install时是根据package.json来安装相关依赖的,但是它里面的版本不固定,因此默认会根据最高的版本来安装相关依赖,但是在npm5是根据pac ...

  4. WSL Windows subsytem linux 的简单学习与使用

    1. win10 1709 以上的版本应该都增加上了 ctrl +r 运行 winver 查看版本 2. 添加删除程序 增加 wsl 增加一个功能 3. 打开cmd 输入 bash 即可 4. 可以将 ...

  5. Linux 下面 Sqlserver 2017 的简单安装

    1. 公司网络太烂 yum 在线安装失败 2. 解决方法 找微软的官网 百度网盘 离线下载rpm包. https://packages.microsoft.com/rhel/7/mssql-serve ...

  6. Linux上的一些基本常用命令

    上传下载文件:// 首先安装lrzsz # yum -y install lrzsz // 上传文件,执行命令rz,会跳出文件选择窗口,选择好文件,点击确认即可.# rz // 下载文件,执行命令sz ...

  7. javap -v没有显示LocalVaribleTable

    时隔多日,终于找到为什么javap -v .class文件没有LocalVariableTable出现 因为默认的javac编译没有生成相关的调试信息,这里我们可以通过javac -help查看指令帮 ...

  8. 校园电商项目2(基于SSM)——模块设计

    步骤一:各模块职责 步骤二:实体类设计 package com.figsprite.o2o.bean; import java.util.Date; public class Area { priva ...

  9. 2.请介绍一下List和ArrayList的区别,ArrayList和HashSet区别

    第一问: List是接口,ArrayList实现了List接口. 第二问: ArrayList实现了List接口,HashSet实现了Set接口,List和Set都是继承Collection接口. A ...

  10. 如何使用nodejs快速搭建本地服务器

    1.首先要安装好node,js 2.以下有安装包下载的链接:这里的安装包是.msi,如果要其他的,可以到菜鸟教程上去找 32 位安装包下载地址 : https://nodejs.org/dist/v4 ...