[SDOI2016]生成魔咒
题目描述
魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 1、2 拼凑起来形成一个魔咒串 [1,2]。
一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。
例如 S=[1,2,1] 时,它的生成魔咒有 [1]、[2]、[1,2]、[2,1]、[1,2,1] 五种。S=[1,1,1] 时,它的生成魔咒有 [1]、[1,1]、[1,1,1] 三种。最初 S 为空串。共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符。每次操作后都需要求出,当前的魔咒串 S 共有多少种生成魔咒。
输入输出格式
输入格式:
第一行一个整数 n。
第二行 n 个数,第 i 个数表示第 i 次操作加入的魔咒字符。
输出格式:
输出 n 行,每行一个数。第 i 行的数表示第 i 次操作后 S 的生成魔咒数量
输入输出样例
说明
对于%10的数据,1≤n≤101 \le n \le 101≤n≤10
对于%30的数据,1≤n≤1001 \le n \le 1001≤n≤100
对于%60的数据,1≤n≤1001 \le n \le 1001≤n≤100
对于%100的数据,1≤n≤1000001 \le n \le 1000001≤n≤100000
用来表示魔咒字符的数字 x 满足1≤n≤1091 \le n \le 10^91≤n≤109
反转字符串,这样就变成了后缀
先后缀数组求出height数组
然后从前往后一个一个加
首先我们知道一个字符串的字串数是每个后缀的长度减去height[i]
每加入一个字符,就新产生一个后缀
那么每添加一个前缀,增加了多少个不同的子串,其实就是在之前添加的前缀中
排名最靠近该前缀的两个串a和b,计算出他们与该前缀的lcp,
然后不同的子串数就是当前添加的前缀长度len-max(lcpa,lcpb)了
找排名最靠近的用线段树
以后模板改了,从1开始,方便很多
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
using namespace std;
typedef long long lol;
int n,m,c[],x[],y[],SA[],s[],b[],rank[],h[];
int Mx[],Mi[],Log[],Min[][];
lol ans;
void radix_sort()
{int i;
for (i=;i<=m;i++)
c[i]=;
for (i=;i<=n;i++)
c[x[y[i]]]++;
for (i=;i<=m;i++)
c[i]+=c[i-];
for (i=n;i>=;i--)
SA[c[x[y[i]]]--]=y[i];
}
void build_SA()
{int i,j,k,p;
for (i=;i<=n;i++)
x[i]=s[i],y[i]=i;
m=;
radix_sort();
for (k=;k<=n;k<<=)
{
p=;
for (i=n-k+;i<=n;i++)
y[++p]=i;
for (i=;i<=n;i++)
if (SA[i]>k) y[++p]=SA[i]-k;
radix_sort();
p=;swap(x,y);
x[SA[]]=;
for (i=;i<=n;i++)
x[SA[i]]=((y[SA[i]]==y[SA[i-]])&&(y[SA[i]+k]==y[SA[i-]+k]))?p:++p;
if (p>=n) break;
m=p;
}
for (i=;i<=n;i++)
rank[SA[i]]=i;
int L=;
for (i=;i<=n;i++)
{
if (L>) L--;
j=SA[rank[i]-];
while (i+L<=n&&j+L<=n&&(s[j+L]==s[i+L])) L++;
h[rank[i]]=L;
}
}
void update(int rt,int l,int r,int x)
{
if (l==r)
{
Mx[rt]=Mi[rt]=x;
return;
}
int mid=(l+r)/;
if (x<=mid) update(rt<<,l,mid,x);
else update(rt<<|,mid+,r,x);
Mx[rt]=max(Mx[rt<<],Mx[rt<<|]);
Mi[rt]=min(Mi[rt<<],Mi[rt<<|]);
}
int query(int rt,int l,int r,int L,int R,int p)
{
if (l>=L&&r<=R)
{
if (p==)
return Mx[rt];
else return Mi[rt];
}
int mid=(l+r)/,mx=,mi=n+;
if (p==)
{
if (L<=mid) mx=max(mx,query(rt<<,l,mid,L,R,p));
if (R>mid) mx=max(mx,query(rt<<|,mid+,r,L,R,p));
return mx;
}
else
{
if (L<=mid) mi=min(mi,query(rt<<,l,mid,L,R,p));
if (R>mid) mi=min(mi,query(rt<<|,mid+,r,L,R,p));
return mi;
}
}
int RMQ(int x,int y)
{
int L=Log[y-x+];
return min(Min[x][L],Min[y-(<<L)+][L]);
}
int main()
{int i,tot,j,tmp;
//freopen("zyys.out","w",stdout);
scanf("%d",&n);
for (i=;i<=n;i++)
{
scanf("%d",&s[n-i+]);
b[i]=s[n-i+];
}
sort(b+,b+n+);
tot=unique(b+,b+n+)-b-;
for (i=;i<=n;i++)
s[i]=lower_bound(b+,b+tot+,s[i])-b;
build_SA();
Log[]=;
for (i=;i<=n;i++)
Log[i]=Log[i/]+;
for (i=;i<=n;i++)
Min[i][]=h[i];
for (j=;(<<j)<=n;j++)
{
for (i=;i<=n-(<<j)+;i++)
Min[i][j]=min(Min[i][j-],Min[i+(<<j-)][j-]);
}
memset(Mx,-/,sizeof(Mx));memset(Mi,/,sizeof(Mi));
update(,,n+,);update(,,n+,n+);
for (i=n;i>=;i--)
{
int now=rank[i];
int pre=query(,,n+,,now-,),nxt=query(,,n+,now+,n+,);
tmp=;
if (pre>=)
tmp=max(tmp,RMQ(pre+,now));
if (nxt<=n)
tmp=max(tmp,RMQ(now+,nxt));
ans+=n-i+-tmp;
printf("%lld\n",ans);
update(,,n+,now);
}
}
[SDOI2016]生成魔咒的更多相关文章
- BZOJ4516: [Sdoi2016]生成魔咒 后缀自动机
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #inclu ...
- BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]
4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...
- BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay
BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔 ...
- P4070 [SDOI2016]生成魔咒
题目地址:P4070 [SDOI2016]生成魔咒 相信看到题目之后很多人跟我的思路是一样的-- 肯定要用 SA(P3809 [模板]后缀排序) 肯定要会求本质不同的子串个数(P2408 不同子串个数 ...
- bzoj4516 / P4070 [SDOI2016]生成魔咒
P4070 [SDOI2016]生成魔咒 后缀自动机 每插入一个字符,对答案的贡献为$len[last]-len[fa[last]]$ 插入字符范围过大,所以使用$map$存储. (去掉第35行就是裸 ...
- 【LG4070】[SDOI2016]生成魔咒
[LG4070][SDOI2016]生成魔咒 题面 洛谷 题解 如果我们不用在线输的话,那么答案就是对于所有状态\(i\) \[ \sum (i.len-i.fa.len) \] 现在我们需要在线询问 ...
- 洛谷 P4070 [SDOI2016]生成魔咒 解题报告
P4070 [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 \(1\).\(2\) 拼凑起来形成一个魔咒串 \([1,2]\). 一个魔咒 ...
- [Sdoi2016]生成魔咒[SAM or SA]
4516: [Sdoi2016]生成魔咒 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1017 Solved: 569[Submit][Statu ...
- 4516: [Sdoi2016]生成魔咒
4516: [Sdoi2016]生成魔咒 链接 题意: 求本质不同的子串. 分析: 后缀数组或者SAM都可以. 考虑SAM中每个点的可以表示的子串是一个区间min(S)~max(S),把每个点的这个区 ...
- [SDOI2016] 生成魔咒 - 后缀数组,平衡树,STL,时间倒流
[SDOI2016] 生成魔咒 Description 初态串为空,每次在末尾追加一个字符,动态维护本质不同的子串数. Solution 考虑时间倒流,并将串反转,则变为每次从开头删掉一个字符,即每次 ...
随机推荐
- 第五次作业-需求&原型改进
需求&原型改进 0. 团队介绍 团队名称:121ComeOn 项目名称:个人博客项目 团队组成: PM:黄金筱(107) 成员:王枫(031),刘烨(255),周明浩(277) github地 ...
- alpha-咸鱼冲刺day1-紫仪
总汇链接 一,合照 emmmmm.自然是没有的. 二,项目燃尽图 三,项目进展 登陆界面随意写了一下.(明天用来做测试的) 把学姐给我的模板改成了自家的个人主页界面,侧边栏啥的都弄出来了(快撒花花 ...
- C语言--第一周作业(更改)
*********************学习总结********************* 1.所用词典: 2.Git截图: *********************遇到的问题和解决方法***** ...
- 201621123057 《Java程序设计》第2周学习总结
一.本周学习总结 基本数据类型 char实质属于整型.boolean类型取值只有true和false两种. 引用数据类型 包装类:自动装箱 与 自动拆箱 数组:一维数组遍历数组用foreach循环:多 ...
- 项目Beta冲刺Day2
项目进展 李明皇 今天解决的进度 优化了信息详情页的布局:日期显示,添加举报按钮等 优化了程序的数据传递逻辑 明天安排 程序运行逻辑的完善 林翔 今天解决的进度 实现微信端消息发布的插入数据库 明天安 ...
- 自己写编程语言-m语言
一直对技术有很强的兴趣,终于,决定要写自己的语言(m语言).那就先从最简单的开始:解释执行器. 一套完整的语言包含的肯定不止解释执行器了,还要有编译器和IDE,也就还要有语法高亮.智能提示等,不过还没 ...
- EMC CX4-480服务器raid磁盘数据恢复案例
[用户信息]上海某公司 [故障描述]需要进行数据恢复的设备是一台EMC CX4的存储服务器,因为硬盘出现故障导致整个存储阵列瘫痪.整个LUN是由7块1TB的硬盘组成的RAID 5.但服务器共有10块硬 ...
- Spark性能优化总结
1. 避免重复加载RDD 比如一份从HDFS中加载的数据 val rdd1 = sc.textFile("hdfs://url:port/test.txt"),这个test.txt ...
- c++中模板是什么?为什么要定义模板?
一.c++中模板是什么? 首先: int Max(int x, int y) { return x > y ? x : y; } float Max(float a,float b) { ret ...
- python入门(12)dict
python入门(12)dict Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例 ...