200209-省选模拟测试2
T1 串
题目描述
题解
AC自动机。
首先对所有串,建立出AC自动机。如果不考虑重复的话显然就有
c
n
t
2
cnt^2
cnt2个。(
c
n
t
cnt
cnt表示AC自动机中节点个数),于是考虑去重。
如果产生重复的话,显然是下图情况:
也就是对于同一个串划分方式不同,黑色处表示划分点。
很显然,红串是蓝串的后缀,而中间圈出来的串为黄串的后缀。于是考虑枚举每一个fail指针不指向根节点的节点(即有后缀的节点),找出这两个串不同的地方(即图中圈出来的串),那么重复数就是以该串为后缀的前缀总数。
代码实现
#include<bits/stdc++.h>
#define int long long
#define M 300009
using namespace std;
int read(){
int f=1,re=0;char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1,ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
int f[M],dep[M],tr[M][26],fail[M],cnt,n,sum[M];
char s[M];
void build(){
int u=0,len=strlen(s+1);
for(int i=1;i<=len;i++){
int c=s[i]-'a';
if(!tr[u][c]) tr[u][c]=++cnt;
f[tr[u][c]]=u,dep[tr[u][c]]=dep[u]+1,u=tr[u][c];
}
}
void getfail(){
queue<int>q;
for(int i=0;i<26;i++)
if(tr[0][i]) q.push(tr[0][i]);
while(q.size()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(!tr[u][i]) tr[u][i]=tr[fail[u]][i];
else{
int x=tr[u][i],y=fail[u];q.push(x);
while(y&&!tr[y][i]) y=fail[y];
fail[x]=tr[y][i];
if(fail[x]) for(int j=fail[x];j;j=fail[j]) sum[j]++;
}
}
}
}
int solve(){
int ans=0;
for(int i=1;i<=cnt;i++)
if(fail[i]){
int x=i,y=fail[x];
for(int j=1;j<=dep[y];j++) x=f[x];
ans+=sum[x];
}return ans;
}
signed main(){
n=read();
for(int i=1;i<=n;i++){
scanf("%s",s+1);
build();
}getfail();
printf("%lld\n",cnt*cnt-solve());
return 0;
}
T2 两个串
题目描述
题解
FFT完成单模式串匹配(含通配符)
见P4173-残缺的字符串
代码实现
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define M 1000009
using namespace std;
const double eps=1e-1;
const double pi=acos(-1.0);
int a[M],b[M],n,m,lim=1,l,r[M],cnt,ans[M];
char s[M],t[M];
struct complex{
double x,y;
complex(double a=0,double b=0){x=a,y=b;}
friend inline complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
friend inline complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
friend inline complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}c[M],d[M],e[M];
void FFT(complex *A,int type){
for(int i=0;i<lim;i++) if(i<r[i]) swap(A[i],A[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
complex W(cos(pi/mid),type*sin(pi/mid));
for(int R=mid<<1,j=0;j<lim;j+=R){
complex w(1,0);
for(int k=0;k<mid;k++,w=w*W){
complex x=A[j+k],y=w*A[j+k+mid];
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
}
}
int main(){
scanf("%s",s);
scanf("%s",t);
n=strlen(s),m=strlen(t);
reverse(t,t+m);
while(lim<n+m) lim<<=1,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<n;i++) a[i]=s[i]-'a'+1;
for(int i=0;i<m;i++){
if(t[i]=='?') b[i]=0;
else b[i]=t[i]-'a'+1;
}
for(int i=0;i<lim;i++) c[i].x=b[i]*b[i]*b[i];
for(int i=0;i<lim;i++) d[i].x=1;
FFT(c,1),FFT(d,1);
for(int i=0;i<lim;i++) e[i]=c[i]*d[i];
for(int i=0;i<lim;i++) c[i].x=2*a[i],c[i].y=0;
for(int i=0;i<lim;i++) d[i].x=b[i]*b[i],d[i].y=0;
FFT(c,1),FFT(d,1);
for(int i=0;i<lim;i++) e[i]=e[i]-(c[i]*d[i]);
for(int i=0;i<lim;i++) c[i].x=a[i]*a[i],c[i].y=0;
for(int i=0;i<lim;i++) d[i].x=b[i],d[i].y=0;
FFT(c,1),FFT(d,1);
for(int i=0;i<lim;i++) e[i]=e[i]+(c[i]*d[i]);
FFT(e,-1);
for(int i=m-1;i<n;i++)
if(fabs(e[i].x/lim)<eps) ans[++cnt]=i-m+1;
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]);
return 0;
}
T3 K个串
题目描述
题解
主席树区间修改
代码实现
#include<bits/stdc++.h>
#define M 100009
using namespace std;
int a[M],nxt[M],b[M],n,m,rt[M*7],idx[M],p[M],cnt;
long long sum[M];
const long long inf=1e17;
bool vis[M];
struct tree{
int l,r,pos;
long long maxn,add;
}tr[M*160];
struct data{
long long rt,pos,val;
data(long long _rt,long long _pos,long long _val){rt=_rt; pos=_pos; val=_val;}
friend bool operator < (data x,data y){return x.val<y.val;}
};
priority_queue<data>q;
void pushup(int k){
tr[k].maxn=max(tr[tr[k].l].maxn,tr[tr[k].r].maxn);
if(tr[tr[k].l].maxn>tr[tr[k].r].maxn) tr[k].pos=tr[tr[k].l].pos;
else tr[k].pos=tr[tr[k].r].pos;
}
void build(int k,int l,int r){
tr[k].l=++cnt,tr[k].r=++cnt;
if(l==r){
tr[k].maxn=sum[l];
tr[k].pos=l;
return;
}int mid=(l+r)>>1;
build(tr[k].l,l,mid);
build(tr[k].r,mid+1,r);
pushup(k);
}
void add(int &k,long long val){
int x=++cnt;
tr[x]=tr[k];
tr[x].add+=val;
tr[x].maxn+=val;
k=x;
}
void pushdown(int k){
if(tr[k].add){
add(tr[k].l,tr[k].add);
add(tr[k].r,tr[k].add);
tr[k].add=0;
}
}
void update(int x,int &y,int l,int r,int ql,int qr,long long val){
pushdown(x);
y=++cnt;
tr[y]=tr[x];
if(l>=ql&&r<=qr) return add(y,val);
int mid=(l+r)>>1;
if(ql<=mid) update(tr[x].l,tr[y].l,l,mid,ql,qr,val);
if(qr>mid) update(tr[x].r,tr[y].r,mid+1,r,ql,qr,val);
pushup(y);
}
void debug(int k,int l,int r){
printf("%d %d %lld %d\n",l,r,tr[k].maxn,tr[k].pos);
if(l==r) return;
int mid=(l+r)>>1;
debug(tr[k].l,l,mid);
debug(tr[k].r,mid+1,r);
}
data query(int k){
return data(k,tr[k].pos,tr[k].maxn);
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}sort(b+1,b+n+1);
int len=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++){
int val=lower_bound(b+1,b+len+1,a[i])-b;
idx[val]=a[i];
a[i]=val;
}
for(int i=1;i<=n;i++){
nxt[p[a[i]]]=i;
p[a[i]]=i;
if(!vis[a[i]]) sum[i]=sum[i-1]+idx[a[i]];
else sum[i]=sum[i-1];
vis[a[i]]=1;
}rt[1]=++cnt;
build(rt[1],1,n);
q.push(query(1));
for(int i=2;i<=n;i++){
if(!nxt[i-1]) update(rt[i-1],rt[i],1,n,i,n,-idx[a[i-1]]);
else if(nxt[i-1]!=i)update(rt[i-1],rt[i],1,n,i,nxt[i-1]-1,-idx[a[i-1]]);
else update(rt[i-1],rt[i],1,n,i,n,0);
update(rt[i],rt[n+1],1,n,i-1,i-1,-inf);
rt[i]=rt[n+1],rt[n+1]=0;
q.push(query(rt[i]));
}
while(m>1){
int w;
data v=q.top();q.pop();
update(v.rt,w,1,n,v.pos,v.pos,-inf);
q.push(query(w));
m--;
}printf("%lld\n",q.top().val);
return 0;
}