HDU6661 Acesrc and String Theory【SA】
Acesrc and String Theory
Problem Description
Acesrc is a famous string theorist at Nanjing University second to none. He insists that we should always say an important thing k times. He also believes that every string that can be obtained by concatenating k copies of some nonempty string is splendid. So, he always teaches newcomers, ``String theory problems are important! String theory problems are important! ... String theory problems are important!"
Today, he wants to examine whether the newcomers remember his instruction. He presents a string consisting of lower case letters and asks them the number of splendid substrings of the presented string. No one can solve this problem, and they will be scolded for hours. Can you help them solve this problem?
Note that equal splendid substrings occurred in different positions should be counted separately
给出一个字符串\(s\),问\(s\)中有多少个子串是有\(k\)个相同串拼接而成的
有个暴力的做法,枚举循环节长度然后哈希,复杂度\(O(\frac{n^2}{k})\)
现在考虑\(O(n\log{n})\)的做法,同样是枚举循环节长度\(len\),然后我们枚举循环节的起始位置,假设现在起始位置是\(pos\),那么我们先找从\(pos\)开始的\(k-1\)个循环节,需要保证每个循环节\(lcp(pos,pos+i\cdot len)\ge len\)
现在有了\(k-1\)个循环节,位置从\(L(pos)\),到\(R(pos+(k-1)\cdot len-1)\),现在要找符合条件的\(k\)循环子串,我们只要知道\(L\)和\(R+1\)的最长公共前缀\(lcp\)和以\(R\)结尾和以\(L+1\)结尾的最长公共后缀\(lcs\),就能知道这个\(k-1\)循环节对答案的贡献,我们显然可以构造一个字符串\(s_{l-pre}s_{l-pre+1}\cdots s_l s_{l+1}\cdots s_r s_{r+1}\cdots s_{r+suf}\),其中\(pre+suf==len && pre\le lcs && suf\le lcp\),所以当\(lcs+lcp\ge len\)的时候,对答案的贡献是\(lcs+lcp-len+1\),注意左边界和右边界的处理情况,有点小细节,防止重复计算
由于枚举循环节,复杂度为调和级数\(O(\sum_{i=1}^{n}\frac{n}{i})=O(n\log n)\)
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 3e5+7;
using LL = int_fast64_t;
LL ret;
int n,K,rk[2][MAXN],sec[MAXN],c[MAXN],sa[2][MAXN],height[2][MAXN],ST[2][MAXN][20];
char s[MAXN],t[MAXN];
void SA(int m, char *s, int *rk, int *sa, int *height){
int *RK = rk, *SEC = sec;
for(int i = 0; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[RK[i]=s[i]]++;
for(int i = 1; i <= m; i++) c[i] += c[i-1];
for(int i = n; i >= 1; i--) sa[c[RK[i]]--] = i;
for(int k = 1; k <= n; k <<= 1){
int p = 0;
for(int i = n - k + 1; i <= n; i++) SEC[++p] = i;
for(int i = 1; i <= n; i++) if(sa[i]>k) SEC[++p] = sa[i]-k;
for(int i = 0; i <= m; i++) c[i] = 0;
for(int i = 1; i <= n; i++) c[RK[SEC[i]]]++;
for(int i = 1; i <= m; i++) c[i] += c[i-1];
for(int i = n; i >= 1; i--) sa[c[RK[SEC[i]]]--] = SEC[i];
swap(RK,SEC);
p = 0;
RK[sa[1]] = ++p;
for(int i = 2; i <= n; i++) RK[sa[i]] = SEC[sa[i]]==SEC[sa[i-1]] and SEC[sa[i]+k]==SEC[sa[i-1]+k] ? p : ++p;
if(p==n) break;
m = p;
}
int k = 0;
for(int i = 1; i <= n; i++) rk[sa[i]] = i;
for(int i = 1; i <= n; i++){
if(rk[i]==1) continue;
if(k) k--;
int j = sa[rk[i]-1];
while(i+k<=n and j+k<=n and s[i+k]==s[j+k]) k++;
height[rk[i]] = k;
}
}
void build_ST(){
for(int i = 1; i <= n; i++){
ST[0][i][0] = height[0][i];
ST[1][i][0] = height[1][i];
}
for(int j = 1; (1<<j) <= n; j++){
for(int i = 1; (i+(1<<j))-1 <= n; i++){
ST[0][i][j] = min(ST[0][i][j-1],ST[0][i+(1<<(j-1))][j-1]);
ST[1][i][j] = min(ST[1][i][j-1],ST[1][i+(1<<(j-1))][j-1]);
}
}
}
int qmin(int tg, int L, int R){
int d = log2(R-L+1);
return min(ST[tg][L][d],ST[tg][R-(1<<d)+1][d]);
}
int lcp(int tg, int l, int r){
int rkl = rk[tg][l], rkr = rk[tg][r];
if(rkl>rkr) swap(rkl,rkr);
return qmin(tg,rkl+1,rkr);
}
void calc(int pos, int len){
for(int i = 1; i < K - 1; i++) if(lcp(0,pos,pos+i*len)<len) return;
int L = pos, R = L + (K-1) * len - 1;
int LCP = min(len,lcp(0,L,R+1));
int LCS = min(len-1,lcp(1,n+1-R,n+1-L+1));
if(LCP+LCS>=len) ret += LCP + LCS - len + 1;
}
void solve(){
ret = 0;
scanf("%d %s",&K,s+1);
n = strlen(s+1);
if(K==1){
printf("%I64d\n",1ll*n*(n+1)/2);
return;
}
for(int i = 1; i <= n; i++) t[i] = s[n+1-i];
SA(128,s,rk[0],sa[0],height[0]);
SA(128,t,rk[1],sa[1],height[1]);
build_ST();
for(int len = 1; len <= n; len++){
for(int i = 1; i <= n; i += len){
if(i+(K-1)*len-1>=n) break;
calc(i,len);
}
}
printf("%I64d\n",ret);
}
int main(){
int T;
for(scanf("%d",&T); T; T--) solve();
return 0;
}
HDU6661 Acesrc and String Theory【SA】的更多相关文章
- Microsoft SQL Server 【Windows 身份验证】和 【sa】都无法登录的解决方案
1.修改启动参数:打开[SQL Server 配置管理器(SQL Server Configuration Manager)]→右键[SQL Server(MSSQLSERVER)]属性→高级(Adv ...
- 557. Reverse Words in a String III【easy】
557. Reverse Words in a String III[easy] Given a string, you need to reverse the order of characters ...
- hdu 6661 Acesrc and String Theory (后缀数组)
大意: 求重复$k$次的子串个数 枚举重复长度$i$, 把整个串分为$n/i$块, 如果每块可以$O(1)$计算, 那么最终复杂度就为$O(nlogn)$ 有个结论是: 以$j$开头的子串重复次数最大 ...
- HDOJ3374 String Problem 【KMP】+【最小表示法】
String Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) T ...
- C++中int与string的相互转换【转】
一.int转string 1.c++11标准增加了全局函数std::to_string: string to_string (int val); string to_string (long val) ...
- 213. String Compression【easy】
Implement a method to perform basic string compression using the counts of repeated characters. For ...
- JAVA的String 类【转】
String类 1.String对象的初始化 由于String对象特别常用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: String s = “abc”; s ...
- bzoj 2251: [2010Beijing Wc]外星联络【SA】
先求SA,然后按字典序从小到大枚举子串,每到一个后缀从长到短枚举子串(跳过长为he[i]的和前一段重复的子串),然后维护一个点p,保证i~p之间最小的he>=当前枚举长度,p是单调向右移的 然后 ...
- poj 2774 Long Long Message【SA】
把两个串接到一起求一个SA,然后找最大的sa[i]和sa[i-1]不是一个串的he[i] #include<iostream> #include<cstdio> #includ ...
随机推荐
- vue中选中弹出框内的表格
一:可多选情况且对应勾选 由于是弹出框形式,所以会出现新增DOM与数据的改变问题,因此要使用$nextTick,不然一开始弹出得时候DOM还没有生成,却要获取DOM会报错:这种多选情况会出现一个bug ...
- IntelliJ IDEA启动界面的秘密:当编程遇到艺术
细心的同学会发现Intellij IDEA每次发版本的时候都会有不同的启动界面背景,都很比较抽象的艺术图像. JetBrains的其它产品也有自己独特的设计. 但是这背后是怎么实现的.有什么寓意却很少 ...
- Ossec 安装并配置邮件通知
Ossec 安装并配置邮件通知 目录 Ossec 安装并配置邮件通知 1. 介绍 2. 软硬件环境 3. 安装步骤 3.1 Server 3.2 Agent 3.3 配置邮件通知 4. 参考资料 1. ...
- kubernets之configMap和secret
一 如何有效且更好的将配置写到pod的容器中 考虑一个问题,就是在传统的应用中,程序里面需要的配置一般以配置文件的形式或者shell脚本里面的参数是在执行的时候在命令行里面进行添加,但是在kuber ...
- Python利用最优化算法求解投资内部收益率IRR【一】
一. 内部收益率和净现值 内部收益率(Internal Rate of Return, IRR)其实要和净现值(Net Present Value, NPV)结合起来讲.净现值指的是某个投资项目给公司 ...
- bootstrap 后端模板
Twitter Bootstrap 框架已经广为人知,用于加快网站,应用程序或主题的界面开发,并被公认为是迄今对于 Web 开发的最有实质性帮助的工具之一.在此之前的,各种各样的界面库伴随着高昂的维护 ...
- 前端知识(二)03-Webpack-谷粒学院
目录 一.什么是Webpack 二.Webpack安装 1.全局安装 2.安装后查看版本号 三.创建项目 1.初始化项目 2.创建src文件夹 3.src下创建common.js 4.src下创建ut ...
- Linux学习安装
Linux学习安装 服务器指的是网络中能对其他机器提供某些服务的计算机系统,相对普通PC, 服务器指的是高性能计算机,稳定性.安全性要求更高 linux安装学习 1.虚拟机 一台硬件的机器 安装vmw ...
- 给定HDFS中某一个目录,输出该目录下的所有文件的读写权限、大小、创建时间、路径等信息,如果该文件是目录,则递归输出该目录下所有文件相关信息。
1 import java.text.SimpleDateFormat; 2 import org.apache.hadoop.fs.*; 3 4 public class E_RecursiveRe ...
- udp 连接
在今天的内容里,我对 UDP 套接字调用 connect 方法进行了深入的分析.之所以对 UDP 使用 connect,绑定本地地址和端口,是为了让我们的程序可以快速获取异步错误信息的通知,同时也可以 ...