AtCoder Beginner Contest 213 F题 题解
F - Common Prefixes
该题也是囤了好久的题目了,看题目公共前缀,再扫一眼题目,嗯求每个后缀与其他后缀的公共前缀的和,那不就是后缀数组吗?对于这类问题后缀数组可是相当在行的。
我们用后缀数组的思想转化下题意就是:
经过后缀排序,我们得到\(height\)数组,考虑排名从小到大依次处理每一个字符串,显然对于一个后缀i而言\(ans(sa[i])=\sum_{j=2}^{i} min_{k=j}^i (a_k)+\sum_{j=i+1}^{n} min_{k=i+1}^j(a_k)\)这样我们可以考虑拆开考虑,只考虑起一个\(\sum\)的结果,可以发现如果我们有办法做第一个的话,第二个只需要到这循环做一遍就可以了。接下来我们只考虑第一个\(\sum\)如何快速计算,一般这种题都有两种思路要么是根据某种数据结构达到快速查询到所需结果的目的,要么是根据i和i-1的关系来从上一个值递推出这个值得结果。第一种办法显然有点想不通,考虑第二种结果,我们将i从1递增看看到底有什么关系,
\(i=1\) 答案为空集
\(i=2\) \(ans=a_2\)
\(i=3\) \(ans=min(a_2,a_3)+a_3\)
\(i=4\) \(ans=min(a_2,a_3,a_4)+min(a_3,a_4)+a_4\)
\(...\)
大致可以得到些结论,当i从2开始递增时,每次都会新增一个数\(a_i\)并且对当前所有的数都和\(a_i\)取min再操作。也就是说,我们每次都要和新来的数比大小,看当前保存的数能否比他小,若新来的数比较小的话就取代之前的数,这不就是单调栈吗?我们可以维护一个递增的单调栈,并且维护下每个数出现的次数,若有元素出站,就将它的次数累加到将它弹出站的元素身上。
查看代码
//不等,不问,不犹豫,不回头.
#include
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair
#define PII pair
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
#define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=2e6+10;
int n,tax[N],rak[N],sa[N],tp[N],height[N],M;
int sack[N],top,cnt[N];
ll ans[N];
char c[N]; inline int read()
{
int x=0,ff=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*ff;
} inline void Qsort()
{
rep(i,0,M) tax[i]=0;
rep(i,1,n) tax[rak[i]]++;
rep(i,1,M) tax[i]+=tax[i-1];
fep(i,n,1) sa[tax[rak[tp[i]]]--]=tp[i];
} inline void Suffixsort()
{
M=75;
rep(i,1,n) rak[i]=c[i]-'0'+1,tp[i]=i;
Qsort();
for(int w=1,p=0;p<n;M=p,w<<=1)
{
p=0;
rep(i,1,w) tp[++p]=n-w+i;
rep(i,1,n) if(sa[i]>w) tp[++p]=sa[i]-w;
Qsort();
swap(tp,rak);
rak[sa[1]]=p=1;
rep(i,2,n) rak[sa[i]]=(tp[sa[i]]tp[sa[i-1]]&&tp[sa[i]+w]tp[sa[i-1]+w])?p:++p;
}
} inline void get_height()
{
int j,k=0;
rep(i,1,n)
{
if(k) k--;
j=sa[rak[i]-1];
while(c[i+k]==c[j+k]) ++k;
height[rak[i]]=k;
}
} inline void solve()
{
rep(i,1,n) ans[i]+=n-i+1;
ll p=0;
rep(i,2,n)
{
int ct=1;
while(top&&height[i]<=height[sack[top]])
{
p-=(ll)height[sack[top]]cnt[top];
ct+=cnt[top];
top--;
}
sack[++top]=i;cnt[top]=ct;
p+=(ll)height[sack[top]]cnt[top];
ans[sa[i]]+=p;
}
top=0;p=0;
fep(i,n-1,1)
{
int ct=1;
while(top&&height[i+1]<=height[sack[top]])
{
p-=(ll)height[sack[top]]cnt[top];
ct+=cnt[top];
top--;
}
sack[++top]=i+1;cnt[top]=ct;
p+=(ll)height[sack[top]]cnt[top];
ans[sa[i]]+=p;
}
rep(i,1,n) putl(ans[i]);
} int main()
{
//freopen("1.in","r",stdin);
get(n);
scanf("%s",c+1);
Suffixsort();
get_height();
solve();
return (0_0);
}
//以吾之血,铸吾最后的亡魂.
AtCoder Beginner Contest 213 F题 题解的更多相关文章
- AtCoder Beginner Contest 215 F题题解
F - Dist Max 2 什么时候我才能突破\(F\)题的大关... 算了,不说了,看题. 简化题意:给定\(n\)个点的坐标,定义没两个点的距离为\(min(|x_i-x_j|,|y_i-y_j ...
- AtCoder Beginner Contest 137 F
AtCoder Beginner Contest 137 F 数论鬼题(虽然不算特别数论) 希望你在浏览这篇题解前已经知道了费马小定理 利用用费马小定理构造函数\(g(x)=(x-i)^{P-1}\) ...
- AtCoder Beginner Contest 068 ABCD题
A - ABCxxx Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement This contes ...
- AtCoder Beginner Contest 053 ABCD题
A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...
- AtCoder Beginner Contest 220部分题(G,H)题解
刚开始的时候被E题卡住了,不过发现是个数学题后就开始使劲推式子,幸运的是推出来了,之后的F题更是树形DP换根的模板吧,就草草的过了,看了一眼G,随便口胡了一下,赶紧打代码,毕竟时间不多了,最后也没打完 ...
- AtCoder Beginner Contest 188 F - +1-1x2 思维题
题目描述 给你两个数 \(x\),\(y\) 可以对 \(x\) 进行 \(+1,-1\) 或 \(\times 2\) 的操作 问最少操作多少次后变为 \(y\) \(x,y \leq 10^{18 ...
- AtCoder Beginner Contest 069 ABCD题
题目链接:http://abc069.contest.atcoder.jp/assignments A - K-City Time limit : 2sec / Memory limit : 256M ...
- AtCoder Beginner Contest 070 ABCD题
题目链接:http://abc070.contest.atcoder.jp/assignments A - Palindromic Number Time limit : 2sec / Memory ...
- AtCoder Beginner Contest 057 ABCD题
A - Remaining Time Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Dol ...
随机推荐
- 【C++基础教程】第三课
上次的课后练习答案 练习一 第一题a=8 第二题8 第三题(int)(a+0.2) 提示:把浮点数转换为整数,用强制类型转换的方式.(int)(...)表示把...的内容强制转换为int类型,同理,( ...
- 【PHP数据结构】图的应用:最小生成树
在学习了图的基本结构和遍历方式后,我们再继续地深入学习一些图的基本应用.在之前的数据结构中,我们并没接触太多的应用场景,但是图的这两类应用确是面试或考试中经常出现的问题,而且出现的频率还非常高,不得不 ...
- 微信小程序生成小程序某一个页面的小程序码
1 登录微信小程序后台,mp.weixin.qq.com 2 点击右上角工具->生成小程序码 3 填写小程序名称或appid 4 关键一步,下面页面填写用户微信号后,打开小程序到某一个页面,点击 ...
- Charles抓包工具过滤网络请求
Charles是一个HTTP代理服务器,HTTP监视器,反转代理服务器,当浏览器连接Charles的代理访问互联网时,Charles可以监控浏览器发送和接收的所有数据.它允许一个开发者查看所有连接互联 ...
- php nginx 路径批量配置
* 假设 E:\upload 作为图片上传的位置 nginx 做web服务 * 创建文件conf.php 放到这个目录下 <?php function handleDir($it, &$ ...
- Python中类-带括号与不带括号的区别
类不带括号我们叫赋值,带括号我们叫实例化. 什么是赋值? a=7 b=a id(7) 140726814208448 id(a) 140726814208448 id(b) 1407268142084 ...
- python json格式化打印
编写python脚本,调试的时候需要打印json格式报文,直接打印看不出层次,可以使用json.dumps格式化打印 import json import requests def test_json ...
- python 文件夹扫描
扫描指定文件夹下的文件.或者匹配指定后缀和前缀的函数. 假设要扫描指定文件夹下的文件,包含子文件夹,调用scan_files("/export/home/test/") 假设要扫描 ...
- 软件开发的V模型
原文来自:http://www.51testing.com/html/67/n-3723567.html 软件开发的V模型大家都不陌生,其中测试阶段分为单元测试->功能测试->系统测试-& ...
- Git:分布式版本控制系统
参考廖雪峰的 Git 教程:https://www.liaoxuefeng.com/wiki/896043488029600 讲解很详细,这里只做一些个人笔记: 各系统安装 Git :https:/ ...