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

  1. Microsoft SQL Server 【Windows 身份验证】和 【sa】都无法登录的解决方案

    1.修改启动参数:打开[SQL Server 配置管理器(SQL Server Configuration Manager)]→右键[SQL Server(MSSQLSERVER)]属性→高级(Adv ...

  2. 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 ...

  3. hdu 6661 Acesrc and String Theory (后缀数组)

    大意: 求重复$k$次的子串个数 枚举重复长度$i$, 把整个串分为$n/i$块, 如果每块可以$O(1)$计算, 那么最终复杂度就为$O(nlogn)$ 有个结论是: 以$j$开头的子串重复次数最大 ...

  4. HDOJ3374 String Problem 【KMP】+【最小表示法】

    String Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  5. C++中int与string的相互转换【转】

    一.int转string 1.c++11标准增加了全局函数std::to_string: string to_string (int val); string to_string (long val) ...

  6. 213. String Compression【easy】

    Implement a method to perform basic string compression using the counts of repeated characters. For ...

  7. JAVA的String 类【转】

    String类 1.String对象的初始化 由于String对象特别常用,所以在对String对象进行初始化时,Java提供了一种简化的特殊语法,格式如下: String s = “abc”; s ...

  8. bzoj 2251: [2010Beijing Wc]外星联络【SA】

    先求SA,然后按字典序从小到大枚举子串,每到一个后缀从长到短枚举子串(跳过长为he[i]的和前一段重复的子串),然后维护一个点p,保证i~p之间最小的he>=当前枚举长度,p是单调向右移的 然后 ...

  9. poj 2774 Long Long Message【SA】

    把两个串接到一起求一个SA,然后找最大的sa[i]和sa[i-1]不是一个串的he[i] #include<iostream> #include<cstdio> #includ ...

随机推荐

  1. linux环境下oracle 11g 静默安装

    安装环境 Linux服务器:oracle linux 6.6 64位 Oracle服务器:Oracle11gR2 64位 系统要求 1.Linux安装Oracle系统要求 系统要求 说明 内存 必须高 ...

  2. 初识sa-token,一行代码搞定登录授权!

    前言 在java的世界里,有很多优秀的权限认证框架,如Apache Shiro.Spring Security 等等.这些框架背景强大,历史悠久,其生态也比较齐全. 但同时这些框架也并非十分完美,在前 ...

  3. Spring Security OAuth2.0认证授权五:用户信息扩展到jwt

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  4. 解决Establishing SSL connection without server‘s identity verification is not recommended.

    每次从数据库中进行查询或者其他操作控制台都会出现以下警告,虽说不是error,但是很显眼.. WARN: Establishing SSL connection without server's id ...

  5. 深入理解MySQL索引(上)

    简单来说,索引的出现就是为了提高数据查询的效率,就像字典的目录一样.如果你想快速找一个不认识的字,在不借助目录的情况下,那我估计你的找好长时间.索引其实就相当于目录. 几种常见的索引模型 索引的出现是 ...

  6. SpringBoot对静态资源的映射规则

    在WebMvcAutoConfiguration类中有相对应的方法addResourceHandlers public void addResourceHandlers(ResourceHandler ...

  7. canvas多重阴影发光效果

    canvas多重阴影发光效果 前言 在一个项目中,客户提了一个发光的效果,效果图如下: 阴影 有的人可能会说,这个用阴影其实就可以实现.但是从图中可以看出,是一个比较强烈的发光效果.实际的应用过程中我 ...

  8. 【Oracle】 并行查询

    所谓并行执行,是指能够将一个大型串行任务(任何DML,一般的DDL)物理的划分为叫多个小的部分,这些较小的部分可以同时得到处理.何时使用并行执行:1.必须有一个非常大的任务 2.必须有充足的资源(CP ...

  9. 惠普电脑(HP PHILIPS系列)安装ubuntu后无法连接WIFI解决方案(手动安装8821CE驱动)

    一步一步来, 先说环境: 我的电脑是HP PHILIPS系列,ubuntu版本是16.04 背景: win10安装ubuntu后发现无法连接wifi(但win10系统可以连接WIFI),在ubuntu ...

  10. 【葵花宝典】一天掌握Docker

    第1章Docker 概述 1-1 Docker是什么 没有虚拟化技术的原始年代 我们仔细想想,在没有计算虚拟化技术的"远古"年代,如果我们要部署一个应用程序(Application ...