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题 题解的更多相关文章

  1. AtCoder Beginner Contest 215 F题题解

    F - Dist Max 2 什么时候我才能突破\(F\)题的大关... 算了,不说了,看题. 简化题意:给定\(n\)个点的坐标,定义没两个点的距离为\(min(|x_i-x_j|,|y_i-y_j ...

  2. AtCoder Beginner Contest 137 F

    AtCoder Beginner Contest 137 F 数论鬼题(虽然不算特别数论) 希望你在浏览这篇题解前已经知道了费马小定理 利用用费马小定理构造函数\(g(x)=(x-i)^{P-1}\) ...

  3. AtCoder Beginner Contest 068 ABCD题

    A - ABCxxx Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement This contes ...

  4. AtCoder Beginner Contest 053 ABCD题

    A - ABC/ARC Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Smeke has ...

  5. AtCoder Beginner Contest 220部分题(G,H)题解

    刚开始的时候被E题卡住了,不过发现是个数学题后就开始使劲推式子,幸运的是推出来了,之后的F题更是树形DP换根的模板吧,就草草的过了,看了一眼G,随便口胡了一下,赶紧打代码,毕竟时间不多了,最后也没打完 ...

  6. AtCoder Beginner Contest 188 F - +1-1x2 思维题

    题目描述 给你两个数 \(x\),\(y\) 可以对 \(x\) 进行 \(+1,-1\) 或 \(\times 2\) 的操作 问最少操作多少次后变为 \(y\) \(x,y \leq 10^{18 ...

  7. AtCoder Beginner Contest 069 ABCD题

    题目链接:http://abc069.contest.atcoder.jp/assignments A - K-City Time limit : 2sec / Memory limit : 256M ...

  8. AtCoder Beginner Contest 070 ABCD题

    题目链接:http://abc070.contest.atcoder.jp/assignments A - Palindromic Number Time limit : 2sec / Memory ...

  9. AtCoder Beginner Contest 057 ABCD题

    A - Remaining Time Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement Dol ...

随机推荐

  1. UVA 11853 Paintball(几何数学+DFS)

    https://vjudge.net/problem/UVA-11853 根据题意描述,相当于在一个正方形中有若干个圆形障碍物,问是否能从左边界走到右边界.判断是否有解需要一点创造性的思维:不妨把正方 ...

  2. CodeForce-812B Sagheer, the Hausmeister(DFS)

    Sagheer, the Hausmeister CodeForces - 812B 题意:有一栋楼房,里面有很多盏灯没关,为了节约用电小L决定把这些灯都关了. 这楼有 n 层,最左边和最右边有楼梯. ...

  3. 做一个U盘的学习路线

    最近想研究一个U盘,然后顺便熟悉一下USB协议.因为USB协议比较复杂, 常用的复杂外设除了WiFi,Ethernet,SDIO和USB这些就是USB了,学习USB的时候肯定要拿一个东西下手,所以简单 ...

  4. quicksort 快速排序 quick sort

    * Java基本版 package cn.mediamix; import java.util.LinkedList; public class QuickSort { public static v ...

  5. flask_sqlalchemy 查询结果转dict 终极解决方案

    之前为了学习Python,试着拿Flask作框架搞小网站,感觉还不错,基本就抛弃了PHP.前段时间做了一个微信小程序,想着yii框架拿来写几十个小接口是不是浪费了,就继续用flask写api了,哪想到 ...

  6. Python日常Bug集

    1.TypeError: 'int' object is not iterable: 场景示例: data = 7 for i in data: print(i) # 原因:直接对int数据进行迭代造 ...

  7. 电商管理后台 API 接口文档

    1. 电商管理后台 API 接口文档 1.1. API V1 接口说明 接口基准地址:http://127.0.0.1:8888/api/private/v1/ 服务端已开启 CORS 跨域支持 AP ...

  8. Mysql explain中key_len的作用及计算规则

    key_len表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要. 在计算key_len时,下面是一些需要考虑的点: 索引字段的附加信 ...

  9. 基于go语言学习工厂模式

    工厂模式 简单工厂模式(Simple Factory) 定义 优点 缺点 适用范围 代码实现 工厂方法模式(Factory Method) 定义 优点 缺点 适用范围 代码实现 抽象工厂模式(Abst ...

  10. 题解「雅礼集训 2017 Day7」事情的相似度

    题目传送门 Description 给出一个长度为 \(n\) 的 \(01\) 串为 \(s\),设 \(t_i\) 为 \(s_{1,2,..,i}\),有 \(m\) 次查询,每次查询给出 \( ...