题目描述

魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示。例如可以将魔咒字符 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. gitignore忽略规则

    我们用git提交本地代码时,有些文件或日志是不需要提交的,这个时候可以用.gitignore来解决这个问题: 首先,我们需要创建一个.gitignore文件,用命令输入 touch .gitignor ...

  2. Alpha冲刺No.9

    一.站立式会议 继续解决真实手机中的问题,如果不能解决,请教助教学姐 数据库备忘录的获取和上传 细化界面设计 二.项目实际进展 用一种奇怪的方式解决了真实手机中的问题,在总结里细说. 完成数据库备忘录 ...

  3. 第五次作业-需求&原型改进

    需求&原型改进 0. 团队介绍 团队名称:121ComeOn 项目名称:个人博客项目 团队组成: PM:黄金筱(107) 成员:王枫(031),刘烨(255),周明浩(277) github地 ...

  4. Beta阶段敏捷冲刺报告-DAY3

    Beta阶段敏捷冲刺报告-DAY3 Scrum Meeting 敏捷开发日期 2017.11.4 会议时间 12:30 会议地点 软工所 参会人员 全体成员 会议内容 当天任务确认,进度调整, 讨论时 ...

  5. 201621123040《Java程序设计》第4周学习总结

    1.本周学习总结 1.1写出你认为本周学习中比较重要的知识点关键词 关键词:继承 多态性 基本语法 重新定义Override 1.2尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多 ...

  6. 每日冲刺报告-Day3

    敏捷冲刺每日报告--Day3 情况简介 今天的任务是把json处理函数加入到爬虫中,把搜索到的结果存到json文件里去. 任务进度 赵坤:在爬虫中加入了json处理的代码,解决了在控制台打印中文列表/ ...

  7. APP案例分析

    产品 蓝叠安卓模拟器 选择理由     看了一眼桌面,就这个比较有意思.现在很多人喜欢玩手游,经常喜欢开个小号搞事情.这时候身边又没有多余的手机,怎么办?安卓模拟器下一个.手机屏幕太小玩起来没意思怎么 ...

  8. Trie树(转)

    原文http://www.cnblogs.com/TheRoadToTheGold/p/6290732.html 一.引入 字典是干啥的?查找字的. 字典树自然也是起查找作用的.查找的是啥?单词. 看 ...

  9. 织梦dedecms默认网站地图sitemap.html优化

    网站地图对于网站优化很重要,搜索引擎就是靠网站地图去收录网站页面,本文主要讲解优化织梦自带的网站地图功能.     织梦自带的网站地图使用方法:织梦后台--生成--HTML更新--更新网站地图,可以在 ...

  10. BizTalk Server 2010高可用方案

    BizTalk Server 2010高可用方案 本文介绍了 Microsoft BizTalk Server 中通过对主机的各层进行扩展提供高可用性的方案. 分隔各个区域的功能分为不同的主机和中的层 ...