luogu3732 [HAOI2017]供给侧改革

题目描述
Anihc国提高社会生产力水平.落实好以人民为中心的发展思想。决定进行供给侧结构性改革。
为了提高供给品质.你调查了某个产业近来n个时期的供求关系平衡情况.每个时期的情况都用0或1中的一个数字来表示.于是这就是—个长度为n的01字符串S。为了更好的了解这一些数据.你需要解决一些询问.我们令data(l,r)表示:在字符串S中.起始位置在[l,r]之间的这些后缀之中,具有最长公共前缀的两个后缀的最长公共前缀的长度。
对于每一个询问L,R.求
a n s = ∑ L ≤ i &lt; R d a t a ( i , R ) ans = \sum_{L\le i &lt; R} data(i,R) ans=Li<Rdata(i,R)
由于你其实根本没有时间调查,所以这些数据都是乱编的,即串S中的每一位都是在0和1之间随机产生的。
输入输出格式
输入格式:
第一行2个整数n,Q,表示字符串的长度,以及询问个数
接下来一行长度为n的一个01串S
接下来Q行,每行2个整数L,R.一个询问L.R
输出格式:
共Q行.每行一个整数.表示对应询问的答案。


s o l u t i o n solution solution
把所有询问按照 r r r排序( l l l也行)
按照起始位置的顺序插入 t r i e trie trie树,同时更新某个长度最后一次出现的最远值

每次询问就从大到小扫一遍数组就行了

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define fr first
#define se second
int rd()
{
	int num = 0;char c = getchar();bool flag = true;
	while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
	while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
	if(flag) return num;else return -num;
}
int n,Q,tot;
int ch[6001000][2],rt,num[101000];
int ans[101000];
P f[6001000];
char s[101000];
vector<P>pl[101000];
struct data{int l,r,id;}q[101000];
bool mycmp(data x,data y){return x.r < y.r || (x.r==y.r && x.l < y.l);}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
void update(int root,int id,int len)
{
	if(f[root].fr == 0) f[root].fr = id;
	else if(f[root].se == 0) f[root].se = id;
	else f[root].fr = f[root].se,f[root].se = id;
    if(f[root].fr && f[root].se) 
		num[len] = max(num[len],f[root].fr);
}
void insert(int i,int j)
{
	int now = rt;
	rep(x,i,j)
	{
		if(!ch[now][s[x]-'0']) ch[now][s[x]-'0'] = ++tot;
		now = ch[now][s[x]-'0'];
	}
	update(now,i,j-i+1);
}
void calc(int r)
{
	rep(x,0,(int)pl[r].size()-1)
	{
		int l = pl[r][x].fr,id = pl[r][x].se;
		int i = l,now = 0;
		repp(j,50,1)
			if(num[j] >= i) now += j*(num[j]-i+1),i = num[j]+1;
		ans[id] = now;
	}
}
int main()
{
    n = rd();Q = rd();rt = ++tot;
	scanf("%s",s+1);
    rep(i,1,Q) q[i].l = rd(),q[i].r = rd(),q[i].id = i;
	sort(q+1,q+Q+1,mycmp);
	rep(i,1,Q) pl[q[i].r].pb(mp(q[i].l,q[i].id));
	rep(i,1,n)
	{
		rep(j,i,min(i+50-1,n)) insert(i,j);
		calc(i);
	}
	rep(i,1,Q) printf("%d\n",ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值