题目描述
做法
lcp长度不超过t,这个概率为1-(1-1/2^t)^(n^2)。
t可以取40。
离线扫描,把询问挂在右端点。
每一个位置把从它开始后长度为40的字符串丢入trie中。
可以在trie的每一个结点保留当前子树中位置最大的两个。
然后可以线段树维护一发。
每次区间max标记可以考虑暴力,均摊复杂度是对的。
你可能不知道我在说什么因为我说的很不详细。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10,maxtot=maxn*40;
int tree[maxn*4],mi[maxn*4],s[maxn];
int g[maxtot][2],fi[maxtot],se[maxtot];
int h[maxn],go[maxn],next[maxn],ask[maxn],ans[maxn],sta[80];
int i,j,k,l,r,t,n,m,tot,top,cnt,lim,root;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
char get(){
char ch=getchar();
while (ch!='0'&&ch!='1') ch=getchar();
return ch;
}
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void change(int p,int l,int r,int a,int b,int v){
if (mi[p]>=v) return;
if (l==r){
tree[p]=mi[p]=v;
return;
}
if (l==a&&r==b){
int mid=(l+r)/2;
change(p*2,l,mid,a,mid,v);
change(p*2+1,mid+1,r,mid+1,b,v);
tree[p]=tree[p*2]+tree[p*2+1];
mi[p]=min(mi[p*2],mi[p*2+1]);
return;
}
int mid=(l+r)/2;
if (b<=mid) change(p*2,l,mid,a,b,v);
else if (a>mid) change(p*2+1,mid+1,r,a,b,v);
else{
change(p*2,l,mid,a,mid,v);
change(p*2+1,mid+1,r,mid+1,b,v);
}
tree[p]=tree[p*2]+tree[p*2+1];
mi[p]=min(mi[p*2],mi[p*2+1]);
}
int query(int p,int l,int r,int a,int b){
if (l==a&&r==b) return tree[p];
int mid=(l+r)/2;
if (b<=mid) return query(p*2,l,mid,a,b);
else if (a>mid) return query(p*2+1,mid+1,r,a,b);
else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b);
}
void insert(int &x,int l,int r,int y){
if (!x) x=++tot;
if (!fi[x]) fi[x]=i;
else{
se[x]=fi[x];
fi[x]=i;
change(1,1,n,1,se[x],y);
}
if (l>r) return;
insert(g[x][s[l]],l+1,r,y+1);
}
void write(int x){
if (!x){
putchar('0');
putchar('\n');
return;
}
top=0;
while (x){
sta[++top]=x%10;
x/=10;
}
while (top) putchar('0'+sta[top--]);
putchar('\n');
}
int main(){
freopen("b.in","r",stdin);freopen("b.out","w",stdout);
n=read();m=read();
fo(i,1,n) s[i]=get()-'0';
lim=min(40,n);
fo(i,1,m){
l=read();r=read();
ask[i]=l;
add(r,i);
}
tot=0;
fo(i,1,n){
if (i+lim-1>n) t=n;else t=i+lim-1;
insert(root,i,t,0);
t=h[i];
while (t){
ans[go[t]]=query(1,1,n,ask[go[t]],i);
t=next[t];
}
}
fo(i,1,m) write(ans[i]);
}