[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开始的LeetCode生活—9. Palindrome Number(回文数)
			
题目大意: 判断输入的数字是不是回文数.所谓回文数就是正反读都一样的数字,比如说11,121,1221这样子的数字.负数不会是回文数. 解题思路: 思路一:如果这个数是负数,则返回false,否则用一 ...
 - Vue.js学习
			
<!DOCTYPE html> <html> <head> <title>xxx</title> </head> <bod ...
 - 几款有用的AndroidStudio插件
			
1.Android Parcelable code generator 顾名思义,这是个生成实现了Parcelable接口的代码的插件. 在你的类中,按下alt + insert键弹出插入代码的上下文 ...
 - phpadmin增加使得项目能连接数据库
			
感谢:http://jingyan.baidu.com/article/e4511cf332b9832b845eaf27.html 值得注意: 1.phpadmin的目录:D:\developsoft ...
 - React 深入系列2:组件分类
			
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列2:组件分类 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加 ...
 - Spark入门(1-3)Spark的重要概念
			
1.什么是弹性分布式数据集? Spark提出了RDD(Resilient Distributed Datasets)这么一个全新的概念,RDD弹性分布式数据集是并行.容错的分布式数据结构:可以将RDD ...
 - C#  读取网页JSON数据
			
场景描述: 公司和别的系统需要对接,现在对方提供一个网址,数据都是json字符串,我需要对json数据进行处理. 提供的json数据如下格式 一.读取网址中的json数据 public string ...
 - nginx nfs服务
			
一.nginx服务 1.二进制安装nginx包 [root@bogon ~]# ls /etc/yum.repos.d/ [root@bogon ~]# cd /etc/yum.repos.d/ [r ...
 - awk、变量、运算符、if多分支
			
awk.变量.运算符.if多分支 awk: 语法 awk [options] 'commands' files option -F 定义字段分隔符,默认的分隔符是连续的空格或制表符 使用option中 ...
 - scrollTop doesn't scroll on Chrome 61
			
在chrome61 不支持滚动 解决方案: Use document.scrollingElement if supported, and fall back to the current code. ...