题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5769 [2016多校contest-4]

题意:给定一个字符,还有一个字符串,问这个字符串存在多少个不同的子串并且子串含有给定的字符。

思路:先忽略包含某个字符的问题,只求一个字符串不同的子串个数,根据<<后缀数组——处理字符串的有力工具>>,每个子串一定是某个后缀的前缀, 那么一个字符串不同的子串个数等价于求所有后缀之问的不相同的前缀的个数 。如果所有的后缀按照 suffix(sa[1]),  suffix(sa[2]), suffix(sa[3]),……,suffix(sa[n])的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1个新的前缀。 但是其中有height[k]个是和前面的字符串的前缀是相同的。 所以 suffix(sa[k])将 ''贡献" 出 n-sa[k]+1- height[k]个不同的子串。累加后便是答案。

然后考虑拥有某个字符的子串,如果要求字符X,只需要记录距离sa[i]最近的字符X的位置(用nxt[sa[i]]表示)即可,即该题的结果为

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<cmath>
using namespace std;
typedef long long int LL;
const int MAXN = + ;
int cmp(int *r, int a, int b, int l){
return r[a] == r[b] && r[a + l] == r[b + l];
}
int wa[MAXN], wb[MAXN], wv[MAXN], WS[MAXN];
void da(int *r, int *sa, int n, int m){
int i, j, p, *x = wa, *y = wb, *t;
for (i = ; i < m; i++) { WS[i] = ; }
for (i = ; i < n; i++) { WS[x[i] = r[i]]++; }
for (i = ; i < m; i++) { WS[i] += WS[i - ]; }
for (i = n - ; i >= ; i--) { sa[--WS[x[i]]] = i; }
for (j = , p = ; p<n; j *= , m = p)
{
for (p = , i = n - j; i < n; i++) { y[p++] = i; }
for (i = ; i < n; i++) {
if (sa[i] >= j){ y[p++] = sa[i] - j; }
}
for (i = ; i < n; i++) { wv[i] = x[y[i]]; }
for (i = ; i < m; i++) { WS[i] = ; }
for (i = ; i < n; i++) { WS[wv[i]]++; }
for (i = ; i < m; i++) { WS[i] += WS[i - ]; }
for (i = n - ; i >= ; i--) { sa[--WS[wv[i]]] = y[i]; }
for (t = x, x = y, y = t, p = , x[sa[]] = , i = ; i < n; i++){
x[sa[i]] = cmp(y, sa[i - ], sa[i], j) ? p - : p++;
}
}
return;
}
int Rank[MAXN], height[MAXN],sa[MAXN];
void calheight(int *r, int *sa, int n){
int i, j, k = ;
for (i = ; i <= n; i++) { Rank[sa[i]] = i; }
for (i = ; i < n; height[Rank[i++]] = k){
for (k ? k-- : , j = sa[Rank[i] - ]; r[i + k] == r[j + k]; k++);
}
return;
}
int t, len,r[MAXN],nxt[MAXN],Ca=;
char str[MAXN],ch[];
LL solve(int n){
LL ans = ;
for (int i = ; i <= n; i++){
ans += 1LL*(n - max(nxt[sa[i]], sa[i] + height[i]));
}
return ans;
}
bool makeNxt(int n){
bool flag = false; int index = n;
for (int i = n - ; i >= ; i--){
if (str[i] == ch[]){
flag = true; index = i;
}
nxt[i] = index;
}
return flag;
}
int main(){
//#ifdef kirito
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
//#endif
// int start = clock();
scanf("%d", &t);
while (t--){
scanf("%s", ch); scanf("%s", str); len = strlen(str);
for (int i = ; i <= len; i++){
if (i == len){ r[i] = ; continue; }
r[i] = (str[i]-'a'+);
}
if (!makeNxt(len)){
printf("Case #%d: 0\n", Ca++);
continue;
}
da(r, sa, len+, );
calheight(r, sa, len);
printf("Case #%d: %I64d\n", Ca++,solve(len));
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

HDU 5769 后缀数组的更多相关文章

  1. hdu 3948 后缀数组

    The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (J ...

  2. HDU - 3948 后缀数组+Manacher

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948 题意:给定一个字符串,求字符串本质不同的回文子串个数. 思路:主要参考该篇解题报告 先按照man ...

  3. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  4. hdu 3518(后缀数组)

    题意:容易理解... 分析:这是我做的后缀数组第一题,做这个题只需要知道后缀数组中height数组代表的是什么就差不多会做了,height[i]表示排名第i的后缀与排名第i-1的后缀的最长公共前缀,然 ...

  5. hdu 5442 (后缀数组)

    稍微学习了下第一次用后缀数组- - , 强行凑出答案 , 感觉现在最大的问题是很多算法都不知道 ,导致有的题一点头绪都没有(就像本题).  /*推荐 <后缀数组——处理字符串的有力工具>— ...

  6. HDU 5558 后缀数组

    思路: 这是一个错误的思路, 因为数据水才过= = 首先求出来后缀数组 把rank插到set里 每回差i两边离i近的rank值,更新 如果LCP相同,暴力左(右)继续更新sa的最小值 //By Sir ...

  7. HDU 4691 后缀数组+RMQ

    思路: 求一发后缀数组,求个LCP 就好了 注意数字有可能不只一位 (样例2) //By SiriusRen #include <bits/stdc++.h> using namespac ...

  8. K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)

    大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置. 这是一篇很好的题解: https://blog.csdn.net/sdauguanweihong/article/ ...

  9. Hdu 1403(后缀数组)

    题目链接 Longest Common Substring Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

随机推荐

  1. c#操作时间

    本年还剩下多少天 private string GetEndTime() { DateTime dt = DateTime.Now; DateTime startYear = DateTime.Now ...

  2. QL Server 实用脚本

    use MyFirstDB; -- 主要内容 -- SQL Server 实用脚本 -- 1.case语句 -- 2.子查询 -- 3.连接查询 -- 4.脚本变量与流程控制(选择与循环等) -- 5 ...

  3. 【XLL API 函数】 xlGetInst

    返回正在调用 DLL 的 Excel 实例的实例句柄. 原型 Excel4(xlGetInst, LPXLOPER pxRes, 0); /* returns low part only */ Exc ...

  4. 【Excel 4.0 函数】REGISTER

    REGISTER.ID 返回指定的 DLL 或 代码资源注册过的函数 ID.如果 DLL 或 代码资源没有注册,这个函数将会注册它们,并返回 注册ID. REGISTER.ID 可以用于工作表(不同于 ...

  5. 【2016-10-11】Linux系统常用的关机或重启命令shutdown、reboot、halt、poweroff、init 0及init 6的联系与区别

    Linux下常用的关机/重启命令一般包括: shutdown.reboot.halt.poweroff等,当然了我们可以使用init 运行等级runlevel 0即halt来关机,或使用init 运行 ...

  6. python 获取控制台输入

    python想从控制台获取输入的的函数有两个一个是raw_input,一个是input. 这两个函数的区别是input获取的时候会精确到类型,假设输入的是1,那么获取的就是int型的变量,如果想输入字 ...

  7. 最长公共上升子序列(codevs 2185)

    题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们要研究最长公共上升子序列了. 小沐沐说,对 ...

  8. nyoj1007(euler 函数)

    euler(x)公式能计算小于等于x的并且和x互质的数的个数: 我们再看一下如何求小于等于n的和n互质的数的和, 我们用sum(n)表示: 若gcd(x, a)=1,则有gcd(x, x-a)=1: ...

  9. 使用detours实现劫持

    第一步:下载detours3.0,安装detours 第二步:构建库文件,nmake编译 第三步:包含库文件和头文件 #include "detours.h" //载入头文件 #p ...

  10. 2 配置Ionic开发环境以及创建新的项目

    1.开发环境需要的软件有: node.js http://nodejs.org  可以到官方网站下载对应平台的安装包安装即可,如果已经安装,需要把它升级到最新的稳定版本   在终端可以输入$node ...