题目传送门

  传送点I

  传送点II

题目大意

  给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量。

  根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid分组。

  分完组考虑如何统计每一组的贡献。

  对于每一组内每一对$(A_i , B_j)$考虑拆成两部分:

  • $rank(A_i) < rank(B_j)$
  • $rank(A_i) > rank(B_j)$

  然后就可以从小到大枚举每一个串,然后考虑前面的$A_i$或$B_j$的贡献。

  显然这个贡献从当前串的前一个串往前走单调不增,然后就拿个单调栈维护就完了。

Code

 /**
* poj
* Problem#3415
* Accepted
* Time: 1110ms
* Memory: 10232k
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#ifndef WIN32
#define Auto "%lld"
#else
#define Auto "%I64d"
#endif
using namespace std;
typedef bool boolean;
#define ll long long #define pii pair<int, int>
#define fi first
#define sc second const int N = 2e5 + ; typedef class Pair3 {
public:
int x, y, id; Pair3() { }
Pair3(int x, int y, int id):x(x), y(y), id(id) { }
}Pair3; typedef class SuffixArray {
protected:
Pair3 T1[N], T2[N];
int cnt[N]; public:
int n;
char *str;
int sa[N], rk[N], hei[N]; void set(int n, char* str) {
this->n = n;
this->str = str;
memset(sa, , sizeof(sa));
memset(rk, , sizeof(rk));
memset(hei, , sizeof(hei));
} void radix_sort(Pair3* x, Pair3* y) {
int m = max(n, );
memset(cnt, , sizeof(int) * m);
for (int i = ; i < n; i++)
cnt[x[i].y]++;
for (int i = ; i < m; i++)
cnt[i] += cnt[i - ];
for (int i = ; i < n; i++)
y[--cnt[x[i].y]] = x[i]; memset(cnt, , sizeof(int) * m);
for (int i = ; i < n; i++)
cnt[y[i].x]++;
for (int i = ; i < m; i++)
cnt[i] += cnt[i - ];
for (int i = n - ; ~i; i--)
x[--cnt[y[i].x]] = y[i];
} void build() {
for (int i = ; i < n; i++)
rk[i] = str[i];
for (int k = ; k < n; k <<= ) {
for (int i = ; i + k < n; i++)
T1[i] = Pair3(rk[i], rk[i + k], i);
for (int i = n - k; i < n; i++)
T1[i] = Pair3(rk[i], , i);
radix_sort(T1, T2);
int diff = ;
rk[T1[].id] = ;
for (int i = ; i < n; i++)
rk[T1[i].id] = (T1[i].x == T1[i - ].x && T1[i].y == T1[i - ].y) ? (diff) : (++diff);
if (diff == n - )
break;
}
for (int i = ; i < n; i++)
sa[rk[i]] = i;
} void get_height() {
for (int i = , j, k = ; i < n; i++, (k) ? (k--) : ()) {
if (rk[i]) {
j = sa[rk[i] - ];
while (i + k < n && j + k < n && str[i + k] == str[j + k]) k++;
hei[rk[i]] = k;
}
}
} const int& operator [] (int p) {
return sa[p];
} const int& operator () (int p) {
return hei[p];
}
}SuffixArray; int K;
int n, m;
char S[N];
SuffixArray sa; inline boolean init() {
scanf("%d", &K);
if (!(K--))
return false;
scanf("%s", S);
n = strlen(S);
S[n] = '#';
scanf("%s", S + n + );
m = strlen(S + n + );
n += m + ;
sa.set(n, S);
return true;
} ll res = , sum;
int tp = ;
pii st[N];
inline void solve(int L, int R) { // Calculate the s_i (i \in [L, R))
if (R - L < )
return ;
tp = sum = ;
for (int i = L, sg; i < R - ; i++) {
sg = (sa[i] < n - m - );
if (!sg)
res += sum;
while (tp && st[tp].fi >= sa(i + ))
sg += st[tp].sc, sum -= st[tp].sc * 1ll * (st[tp].fi - K), tp--;
sum += (sa(i + ) - K) * 1ll * sg;
st[++tp] = pii(sa(i + ), sg);
}
if (!(sa[R - ] < n - m - ))
res += sum; tp = sum = ;
for (int i = L, sg; i < R - ; i++) {
sg = !(sa[i] < n - m - );
if (!sg)
res += sum;
while (tp && st[tp].fi >= sa(i + ))
sg += st[tp].sc, sum -= st[tp].sc * 1ll * (st[tp].fi - K), tp--;
sum += (sa(i + ) - K) * 1ll * sg;
st[++tp] = pii(sa(i + ), sg);
}
if (sa[R - ] < n - m - )
res += sum;
} inline void solve() {
res = ;
sa.build();
sa.get_height(); int lst = ;
for (int i = ; i < n; i++)
if (sa(i) < K + )
solve(lst, i), lst = i;
solve(lst, n);
printf(Auto"\n", res);
} int main() {
while (init())
solve();
return ;
}

poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈的更多相关文章

  1. poj 3415 Common Substrings —— 后缀数组+单调栈

    题目:http://poj.org/problem?id=3415 先用后缀数组处理出 ht[i]: 用单调栈维护当前位置 ht[i] 对之前的 ht[j] 取 min 的结果,也就是当前的后缀与之前 ...

  2. poj 3415 Common Substrings——后缀数组+单调栈

    题目:http://poj.org/problem?id=3415 因为求 LCP 是后缀数组的 ht[ ] 上的一段取 min ,所以考虑算出 ht[ ] 之后枚举每个位置作为右端的贡献. 一开始想 ...

  3. poj 3415 Common Substrings 后缀数组+单调栈

    题目链接 题意:求解两个字符串长度 大于等于k的所有相同子串对有多少个,子串可以相同,只要位置不同即可:两个字符串的长度不超过1e5; 如 s1 = "xx" 和 s2 = &qu ...

  4. POJ - 3415 Common Substrings (后缀数组)

    A substring of a string T is defined as: T( i, k)= TiTi +1... Ti+k -1, 1≤ i≤ i+k-1≤| T|. Given two s ...

  5. POJ 3415 Common Substrings 后缀数组+并查集

    后缀数组,看到网上很多题解都是单调栈,这里提供一个不是单调栈的做法, 首先将两个串 连接起来求height   求完之后按height值从大往小合并.  height值代表的是  sa[i]和sa[i ...

  6. POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)

    Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...

  7. POJ 3415 Common Substrings ——后缀数组

    [题目分析] 判断有多少个长度不小于k的相同子串的数目. N^2显然是可以做到的. 其实可以维护一个关于height的单调栈,统计一下贡献,就可以了. 其实还是挺难写的OTZ. [代码] #inclu ...

  8. Poj 1743 Musical Theme(后缀数组+二分答案)

    Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 28435 Accepted: 9604 Descri ...

  9. Poj 3261 Milk Patterns(后缀数组+二分答案)

    Milk Patterns Case Time Limit: 2000MS Description Farmer John has noticed that the quality of milk g ...

随机推荐

  1. passwd命令

    passwd命令用于设置用户的认证信息,包括用户密码.密码过期时间等.系统管理者则能用它管理系统用户的密码.只有管理者可以指定用户名称,一般用户只能变更自己的密码. 语法 passwd(选项)(参数) ...

  2. hibernate11--Criteria查询

    public class EmpTest { Session session =null; Transaction transaction=null; @Before public void befo ...

  3. 【漏洞复现】Tomcat CVE-2017-12615 远程代码执行漏洞

    漏洞描述 [漏洞预警]Tomcat CVE-2017-12615远程代码执行漏洞/CVE-2017-12616信息泄漏 https://www.secfree.com/article-395.html ...

  4. 关于js执行机制的理解

    js是单线程语言.指的是js的所以程序执行通过仅有的这一个主线程来执行. 但是还有辅助线程,包括定时器线程,ajax请求线程和事件线程. js的异步我理解的是: 主线程执行时候,从上到下依次执行,遇到 ...

  5. python3中报错AttributeError: module 'sys' has no attribute 'setdefaultencoding'

    reload(sys) sys.setdefaultencoding("utf-8") f = open('.\\24.novel.txt','rb') str = f.read( ...

  6. Exception occurred during processing request: id to load is required for loading

    ERROR Dispatcher:38 - Exception occurred during processing request: id to load is required for loadi ...

  7. IntelliJ IDEA 注册码激活

    IntelliJ IDEA 注册码激活 方法一:使用激活服务器激活方法 步骤 1.打开注册/激活窗口: 2.选择 License server: 3.填入上述其中一个网址(如:http://idea. ...

  8. 《Maven实战》文字版[PDF]

    从亚马逊买的电子书,导出来的,需要的下吧. 下面是截图: 除了代码部分有一点点不清楚之外,其他还是蛮清楚的. 下载地址: http://download.csdn.net/download/apple ...

  9. Tensorflow之调试(Debug)及打印变量

    参考资料:https://wookayin.github.io/tensorflow-talk-debugging 几种常用方法: 1.通过Session.run()获取变量的值 2.利用Tensor ...

  10. Ocelot:API网关概要

    一.概要 Ocelot是.Net Core下一个开源API网关:Ocelot主要目标是在.NET在微服务或面向服务架构中提供统一的入口服务, Ocelot拿到HttpRequest对象到管道后,先创建 ...