题目描述

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 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 的生成魔咒数量

输入输出样例

输入样例#1:
复制

7
1 2 3 3 3 1 2
输出样例#1: 复制

1
3
6
9
12
17
22

说明

对于%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]生成魔咒的更多相关文章

  1. BZOJ4516: [Sdoi2016]生成魔咒 后缀自动机

    #include<iostream> #include<cstdio> #include<cstring> #include<queue> #inclu ...

  2. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]

    4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...

  3. BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay

    BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔 ...

  4. P4070 [SDOI2016]生成魔咒

    题目地址:P4070 [SDOI2016]生成魔咒 相信看到题目之后很多人跟我的思路是一样的-- 肯定要用 SA(P3809 [模板]后缀排序) 肯定要会求本质不同的子串个数(P2408 不同子串个数 ...

  5. bzoj4516 / P4070 [SDOI2016]生成魔咒

    P4070 [SDOI2016]生成魔咒 后缀自动机 每插入一个字符,对答案的贡献为$len[last]-len[fa[last]]$ 插入字符范围过大,所以使用$map$存储. (去掉第35行就是裸 ...

  6. 【LG4070】[SDOI2016]生成魔咒

    [LG4070][SDOI2016]生成魔咒 题面 洛谷 题解 如果我们不用在线输的话,那么答案就是对于所有状态\(i\) \[ \sum (i.len-i.fa.len) \] 现在我们需要在线询问 ...

  7. 洛谷 P4070 [SDOI2016]生成魔咒 解题报告

    P4070 [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 \(1\).\(2\) 拼凑起来形成一个魔咒串 \([1,2]\). 一个魔咒 ...

  8. [Sdoi2016]生成魔咒[SAM or SA]

    4516: [Sdoi2016]生成魔咒 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 569[Submit][Statu ...

  9. 4516: [Sdoi2016]生成魔咒

    4516: [Sdoi2016]生成魔咒 链接 题意: 求本质不同的子串. 分析: 后缀数组或者SAM都可以. 考虑SAM中每个点的可以表示的子串是一个区间min(S)~max(S),把每个点的这个区 ...

  10. [SDOI2016] 生成魔咒 - 后缀数组,平衡树,STL,时间倒流

    [SDOI2016] 生成魔咒 Description 初态串为空,每次在末尾追加一个字符,动态维护本质不同的子串数. Solution 考虑时间倒流,并将串反转,则变为每次从开头删掉一个字符,即每次 ...

随机推荐

  1. Active MQ 实战(一)

    1.什么是JMS JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送 ...

  2. c# 动态实例化一个泛型类

    动态实例化一个类,比较常见,代码如下 namespace ConsoleApp2 { public class MyClass { } } Type classType = Type.GetType( ...

  3. RPC原理解析

    1.RPC原理解析 1.1 什么是RPC RPC(Remote Procedure Call Protocol) --远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络 ...

  4. 从Firefox升级说学习方法

    今天早上,打开PortableAPPs时,它提示我升级FireFox,跟往常一样我没考虑就升级了. 打开Firefox 57神速,很是惊喜,打开后发现悲剧了,自己(通过下载插件)定制的功能都不能使用了 ...

  5. scrapy 数据存储mysql

    #spider.pyfrom scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Ru ...

  6. LeetCode & Q14-Longest Common Prefix-Easy

    String Description: Write a function to find the longest common prefix string amongst an array of st ...

  7. Python内置函数(39)——help

    英文文档: help([object]) Invoke the built-in help system. (This function is intended for interactive use ...

  8. 新概念英语(1-139)Is that you, John?

    Lesson 139 Is that you, John? 是你吗,约翰? Listen to the tape then answer this question. Which John Smith ...

  9. ELK学习总结(3-3)elk的组合查询

    1.bool 查询: must: 必须 should:  可以满足,也可以不满足. must_not: minimum_should_match: 至少要x个匹配才算匹配成功 disable_coor ...

  10. 【已解决】React中配置Sass引入.scss文件无效

    React中配置Sass引入.scss文件无效 在react中使用sass时,引入.scss文件失效 尝试很多方法没法解决,最终找到解决方法,希望能帮助正在坑里挣扎的筒子~ 在node_modules ...