[loj#2313] [HAOI2017] 供给侧改革

题意简述

给定一个随机生成的长度为 \(n\) 的由0和1构成的字符串 \(S\)

\(data(l,r)\) 表示:在字符串 \(S\) 中,起始位置在 \([l,r]\) 之间的这些后缀之中,具有最长公共前缀的两个后缀的最长公共前缀的长度。

\(m\) 次询问,每次给定 \(l,r\) ,求 \(\sum\limits_{l\leq i < r} data(i,r)\) ,不强制在线。

\(n,m \leq 10^5\)


想法

注意到“随机生成”,那么两个长度为 \(x\) 的字符串完全相同的概率为 \(\frac{1}{2^x}\)
\(x=40\) 时这个概率就很小了,所以可认为最长公共前缀的长度 \(\leq 40\)
将询问离线,按 \(r\) 从小到大排序。
维护一棵深度40的 \(trie\) 树。
从左到右扫,\(trie\) 树中起始位置在 \(i\) 的后缀。
显然 \(data(1,i)\geq data(2,i) \geq ... \geq data(i-1,i)\)
维护数组 \(h[]\),其中 \(h[x]=y\) 表示 \(y\) 是满足 \(data(y,i)\geq x\) 的最大值。
换句话说,\(data(1,i)\geq data(2,i) \geq ... \geq data(y,i) \geq x > data(y+1,i)\)

那么对于所有 \(r=i\) 的询问,将 \(h[]\) 扫一遍,与 \(l\) 比比大小再运算便可得到 \(ans\) ,因为 \(h[]\) 下标最大40,所以时间上不成问题。

最后一个问题,每加入一个新后缀时,如何更新 \(h[]\) 呢?
\(trie\) 树中每个点 \(x\) 都记录一下之前最后访问该点的那个后缀的起始位置 \(lst[x]\),新加入的后缀走到深度为 \(d\) 的点 \(x\) 时,\(lst[x]\) 开头的后缀与此新后缀的公共前缀至少为 \(d\) ,也就是 \(data(lst[x],i)\geq d\) ,所以更新 \(h[d]=max(h[d],lst[x])\)

总复杂度 \(O(40n)\)


总结

抓住“随机”找特点;抓住小的数据点。
(感觉这个题有点神,虽然代码很短但不太好想……)


代码

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
	return x;
}

const int N = 100005;

int n,m;
char s[N];
struct data{
	int l,r,id;
	bool operator < (const data &b) const{ return r<b.r; }
}d[N];
int ans[N],h[45];

int cnt,root,ch[N*40][2],lst[N*40];
void ins(int id){
	int x=root,y;
	for(int i=0;i<40 && i+id<=n;i++){
		y=s[i+id]-'0';
		if(!ch[x][y]) ch[x][y]=++cnt;
		x=ch[x][y];
		h[i+1]=max(h[i+1],lst[x]);
		lst[x]=id;
	}
}

int main()
{
	n=read(); m=read();
	scanf("%s",s+1);
	for(int i=1;i<=m;i++) d[i].l=read(),d[i].r=read(),d[i].id=i;
	sort(d+1,d+1+m);
	
	root=++cnt;
	int t=1;
	for(int i=1;i<=n;i++){
		if(t>m) break;
		ins(i);
		for(int j=39;j>0;j--) h[j]=max(h[j],h[j+1]);
		while(t<=m && d[t].r==i){
			for(int j=1;j<=40;j++){
				if(h[j]<d[t].l) break;
				ans[d[t].id]+=h[j]-d[t].l+1;
			}
			t++;
		}
	}
	for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
	
	return 0;
} 
posted @ 2020-02-25 20:38  秋千旁的蜂蝶~  阅读(131)  评论(0编辑  收藏  举报