acdream1116 Gao the string!(hash二分 or 后缀数组)
问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数。我一开始做的时候想了好久,后来看了别人的解法才恍然大悟。对于一个后缀来说 s[i...n-1]来说,所有与它匹配的前缀必然是和 s[i+1...n-1] s[i+2...n-1] ....s[n-1..n-1]里的前缀匹配的,因而如果我们定义一个num[i]表示的是后缀s[i...n-1]与前缀的总长公共前缀,那么num[i]+num[i+1]+..num[n-1]就是前缀在后缀i里出现的次数总和,所以问题转化为求s[i...n-1]跟前缀的最长公共前缀,也可以理解成是 s[0...n-1]和s[i...n-1]求最长公共前缀。
求后缀的最长公共前缀,一个做法是后缀数组,然后建lcp,然后通过rmq询问,理论的复杂度nlogn,我自己套的模板用的是快排,所以后缀数组本身的复杂度就已经是nlog^2n,然后我就愉快的TLE了。
失败之后就只能转而用hash+二分,毕竟二分还是慢,所以我卡着时限过了这题,心有余悸。
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <algorithm>
using namespace std; #define maxn 110000
#define ll long long
#define mod 1000000007
#define step 31 /*int rk[maxn], sa[maxn], lcp[maxn];
int tmp[maxn];
int d[maxn + 50][25];*/ int n; /*bool cmp_sa(int i, int j)
{
if (rk[i] != rk[j]) return rk[i] < rk[j];
else{
int ri = i + k <= n ? rk[i + k] : -1;
int rj = j + k <= n ? rk[j + k] : -1;
return ri < rj;
}
} void construct_sa(char *s, int *sa)
{
n = strlen(s);
for (int i = 0; i <= n; i++){
sa[i] = i;
rk[i] = i < n ? s[i] : -1;
}
for (k = 1; k <= n; k <<= 1){
sort(sa, sa + n + 1, cmp_sa);
tmp[sa[0]] = 0;
for (int i = 1; i <= n; i++){
tmp[sa[i]] = tmp[sa[i - 1]] + (cmp_sa(sa[i - 1], sa[i]) ? 1 : 0);
}
for (int i = 0; i <= n; i++){
rk[i] = tmp[i];
}
}
} void construct_lcp(char *s, int *sa, int *lcp)
{
n = strlen(s);
for (int i = 0; i <= n; i++) rk[sa[i]] = i;
int h = 0;
lcp[0] = 0;
for (int i = 0; i < n; i++){
int j = sa[rk[i] - 1];
for (h ? h-- : 0; i + h < n&&j + h < n&&s[i + h] == s[j + h]; h++);
lcp[rk[i] - 1] = h;
}
} void construct_rmq(int *lcp, int sizen)
{
for (int i = 0; i <= sizen; i++) d[i][0] = lcp[i];
for (int j = 1; (1 << j) <= sizen; j++){
for (int i = 0; (i + (1 << j) - 1) <= sizen; i++){
d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
}
}
} int rmq_query(int l, int r)
{
if (l > r) swap(l, r); r -= 1;
int k = 0; int len = r - l + 1;
while ((1 << (k + 1)) < len) k++;
return min(d[l][k], d[r - (1 << k) + 1][k]);
} */ char s[maxn];
ll num[maxn]; struct Matrix
{
ll a[2][2];
Matrix(){ memset(a, 0, sizeof(a)); }
}m; Matrix operator * (const Matrix &a,const Matrix &b){
Matrix ret;
for (int i = 0; i < 2; i++){
for (int j = 0; j < 2; j++){
for (int k = 0; k < 2; k++){
ret.a[i][j] += (a.a[i][k] * b.a[k][j]) % mod;
ret.a[i][j] %= mod;
}
}
}
return ret;
}
Matrix operator ^ (Matrix a,ll n){
Matrix ret;
for (int i = 0; i < 2; i++) ret.a[i][i] = 1;
while (n){
if (n & 1) ret = ret*a;
n >>= 1;
a = a*a;
}
return ret;
} ll cal(ll n)
{
m.a[0][0] = 0; m.a[0][1] = 1;
m.a[1][0] = 1; m.a[1][1] = 1;
m = m^n;
return m.a[0][1];
} ll seed[maxn];
ll h[maxn]; ll get(int l, int r){
return ((h[r] - h[l - 1] * seed[r - l + 1]%mod) + mod) % mod;
} int getlcp(int x)
{
if (get(1, 1) != get(x, x)) return 0;
int l = 1,r = n - x + 1;
while (l <= r){
int m = (l + r) >> 1;
if (get(1, 1 + m - 1) == get(x, x + m - 1)) l = m+1;
else r = m-1;
}
return r;
} int main()
{
seed[0] = 1;
for (int i = 1; i < maxn; i++){
seed[i] = seed[i - 1] * step%mod;
}
while (~scanf("%s", s + 1))
{
n = strlen(s + 1); h[0] = 0;
for (int i = 1; i <= n; i++){
h[i] = (h[i - 1] * step + s[i]) % mod;
}
num[1] = n;
for (int i = 2; i <= n; i++){
num[i] = getlcp(i);
}
ll ans = 0;
num[n + 1] = 0;
for (int i = n; i >= 1; i--){
num[i] += num[i + 1];
ans += cal(num[i]);
ans %= mod;
}
printf("%lld\n", ans);
}
return 0;
}
acdream1116 Gao the string!(hash二分 or 后缀数组)的更多相关文章
- acdream1116 Gao the string!(扩展KMP)
今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是 ...
- BZOJ 1717: [Usaco2006 Dec]Milk Patterns 产奶的模式( 二分答案 + 后缀数组 )
二分答案m, 后缀数组求出height数组后分组来判断. ------------------------------------------------------------ #include&l ...
- bzoj 4310 跳蚤 二分答案+后缀数组/后缀树
题目大意 给定\(k\)和长度\(\le10^5\)的串S 把串分成不超过\(k\)个子串,然后对于每个子串\(s\),他会从\(s\)的所有子串中选择字典序最大的那一个,并在选出来的\(k\)个子串 ...
- BZOJ3796 Mushroom追妹纸(二分答案+后缀数组+KMP)
求出一个串使得这个串是\(s1,s2\)的子串.串中不包含\(s3\). 如果没有这个\(s3\)就可以二分答案,然后height小于二分值分一组.看看每组里是不是出现过\(s1,s2\)的后缀.判断 ...
- poj 1743 二分答案+后缀数组 求不重叠的最长重复子串
题意:给出一串序列,求最长的theme长度 (theme:完全重叠的子序列,如1 2 3和1 2 3 or 子序列中每个元素对应的差相等,如1 2 3和7 8 9) 要是没有差相等这个条件那就好办 ...
- 2018.11.24 poj1743Musical Theme(二分答案+后缀数组)
传送门 代码: 二分答案. 然后对于预处理的heightheightheight数组分成几段. 保证每一段中都是连续的几个heightheightheight并且这些heightheightheigh ...
- [BZOJ4556][TJOI2016&&HEOI2016]字符串(二分答案+后缀数组+RMQ+主席树)
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 1360 Solved: 545[S ...
- poj 3261 二分答案+后缀数组 求至少出现k次的最长重复子序列
#include "stdio.h" #define maxn 20010 int wa[maxn],wb[maxn],wv[maxn],ws[maxn]; int rank[ma ...
- 2018.11.24 poj3261Milk Patterns(后缀数组)
传送门 后缀数组经典题. 貌似可以用二分答案+后缀数组? 我自己yyyyyy了一个好写一点的方法. 直接先预处理出heightheightheight数组. 然后对于所有连续的k−1k-1k−1个he ...
随机推荐
- SQL1092N The requested command or operation failed because the user ID does not have the authority to perform the requested command or operation.
1.前一天安装号db2后,做了如下处理: ************************************************************ 修改 /etc/sudoers 文件 ...
- python中的lambda
lambda表达式返回一个函数对象 例子: func = lambda x,y:x+y func相当于下面这个函数 def func(x,y): return x+y 注意def是语句而lambda是 ...
- 如何在ios 系统 中抓包??
为了实现在ios系统上抓包,如下步骤: 1,设备越狱 2,在cydia-软件源-设置中改为开发者,否则有些deb搜索不到 安装如下软件:OpenSSH,OpenSSL,wget (下载工具) Apti ...
- Hive与HBase区别
对于刚接触大数据的用户来说,要想区分Hive与HBase是有一定难度的.本文将尝试从其各自的定义.特点.限制.应用场景等角度来进行分析,以作抛砖引玉之用. ====Hive是什么?Apache Hiv ...
- Linux下cron的使用
cron是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业.由于Cron 是Linux的内置服务,但它不自动起来,可以用以下的方法启动.关闭这个服务: /sbin/service c ...
- [转]WinExec、ShellExecute和CreateProcess及返回值判断方式
[转]WinExec.ShellExecute和CreateProcess及返回值判断方式 http://www.cnblogs.com/ziwuge/archive/2012/03/12/23924 ...
- Java Day 12
包 编译格式 javac -d . **.java 包之间的访问 类找不到: 类名写错,包名.类名 包不存在:指定classpath 其他包的类无法访问:权限 public protected 包导入 ...
- 【Validate Binary Search Tree】cpp
题目: Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is define ...
- ASP.NET本质论阅读----线程与异步
线程 概要:操作系统通过线程对程序的执行进行管理 线程的数据结构:1.线程的核心对象(包含线程的当前寄存器状态),调用线程时-寄存器状态被加载到CPU中. 2.线程环境块TEB:一块用户模式下的内存 ...
- Spring 静态资源配置
ShineJaie 原创整理,转载请注明出处. 一.为何要配置静态资源 1.在配置 Spring 的时候,我们配置的拦截是"/",即任何文件都会经 Spring 拦截处理. 2.实 ...