P7937 [COCI2007-2008#5] BAZA 题解
masterhuang · · 题解
背景:校内模拟赛出过这题的弱化版,当时 trie+unrodered_map 这种大空间的东西都放过了,时间缩紧了,要求
解法
把每个串都用 '{' 填充为长度
把所有串按前
对于所有和原来第
每次查询也像上面那样填充。先二分前
1.若给定串中有等于查询串的串。
设最小位置为
刚才记录的
有一个细节,设查询串大小为
2.若给定串中没有等于查询串的串。
对于所有
把
复杂度
丑陋的代码:
#include<bits/stdc++.h>
#define P pair<int,int>
#define fi first
#define se second
using namespace std;
const int N=3e4+5;
int n,m,t,b[35][N],c[35][N],tt[35],fir[N],d[N],e[35][N],ans,u[35],L,v[35][N];
char a[N][35],f[35];
vector<P>g;
inline int lb(int x){return x&-x;}
inline void add(int wz,int x){for(;wz<=n;wz+=lb(wz)) d[wz]+=x;}
inline int ask(int wz){int s=0;for(;wz;wz-=lb(wz)) s+=d[wz];return s;}
inline bool cmp(int x,int y){return a[x][t]<a[y][t];}
inline bool eq(char *A,char *B,int x)
{
for(int i=0;i<=x;i++) if(A[i]!=B[i]) return 0;
return 1;
}
inline bool xd(char *A,char *B,int x)
{
for(int i=0;i<=x;i++)
{
if(A[i]<B[i]) return 1;
if(A[i]>B[i]) return 0;
}
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",a[i]),t=strlen(a[i]);
for(int j=t;j<30;j++) a[i][j]='{';
}
for(int i=1;i<=n;i++) b[0][i]=i;g.push_back({1,n});
for(t=0;t<30;t++)
{
for(int i=1;i<=n;i++) b[t+1][i]=b[t][i];//只有b的t +1
for(P &i:g) sort(b[t+1]+i.fi,b[t+1]+i.se+1,cmp);
for(int i=1;i<=n;i++)
{
if(i==1||!eq(a[b[t+1][i-1]],a[b[t+1][i]],t)) c[t][++tt[t]]++,fir[tt[t]]=i;
else c[t][tt[t]]++;
}g.clear();
for(int i=1;i<=tt[t];i++) g.push_back({fir[i],fir[i]+c[t][i]-1});
for(P &i:g)
{
for(int j=i.fi;j<=i.se;j++) add(b[t+1][j],1);
for(int j=i.fi;j<=i.se;j++) e[t][b[t+1][j]]=ask(b[t+1][j]),v[t][b[t+1][j]]=i.se-i.fi+1;
for(int j=i.fi;j<=i.se;j++) add(b[t+1][j],-1);
}
}
scanf("%d",&m);
while(m--)
{
scanf("%s",f);L=strlen(f);for(int i=L;i<30;i++) f[i]='{';ans=0;
int l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(xd(f,a[b[30][mid]],29)) r=mid-1,t=mid;
else l=mid+1;
}
if(!eq(f,a[b[30][t]],29)) t=-1;memset(u,0,sizeof(u));
if(t!=-1)
{
t=b[30][t];for(int i=0;i<30;i++) u[i]=e[i][t];
for(int i=0;i<29;i++) u[i]-=u[i+1];u[L-1]+=u[29];u[29]=0;
for(int i=0;i<30;i++) ans+=(i+1)*u[i];
printf("%d\n",ans+t);
}
else
{
for(int i=0;i<30;i++)
{
int l=1,r=n,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(xd(f,a[b[i+1][mid]],i)) r=mid-1,t=mid;
else l=mid+1;
}
if(eq(f,a[b[i+1][t]],i)) t=b[i+1][t],u[i]=v[i][t];
else break;
}
for(int i=0;i<29;i++) u[i]-=u[i+1];
for(int i=0;i<30;i++) ans+=(i+1)*u[i];
printf("%d\n",ans+n);
}
}
return 0;
}