题目:http://poj.org/problem?id=3415

先用后缀数组处理出 ht[i];

用单调栈维护当前位置 ht[i] 对之前的 ht[j] 取 min 的结果,也就是当前的后缀与之前后缀的LCP,其中长度 >= K 的加到答案;

因为单调栈中是一段一段阶梯状的,只存了一段端点的位置,所以再记录一个 cnt 表示这一段的长度,算贡献时乘上 cnt;

因为是两个串之间,所以先统计 B 在 A 排名前的答案,再重复一遍统计 A 在 B 排名前的答案;

但是 ht[i] 是 sa[i] 和 sa[i-1] 的LCP,所以 ht[i] 是否计入贡献应该考虑 i-1 位置...突然变得很麻烦,不太会弄了...

于是参考了一下TJ(囧),原来就是判断一下 i-1 是否要被统计,如果要统计 B 而 i-1 是 B 中的,就把 ht[i] 也累加到 sum 中;

还有一个很好的操作是如果 ht[i] < K,那么取 min 显然都会取成 < K 的,没贡献了,所以直接 sum=0 , top = 0,就省去了 max(0,ht[i]-K+1) 的分类麻烦。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=1e5+,xxn=(xn<<);//xxn
int n,m,tax[xxn],sa[xxn],rk[xxn],tp[xxn],ht[xxn],sta[xxn],top,cnt[xxn];
char a[xn],b[xn],s[xxn];
void Rsort()
{
for(int i=;i<=m;i++)tax[i]=;
for(int i=;i<=n;i++)tax[rk[tp[i]]]++;
for(int i=;i<=m;i++)tax[i]+=tax[i-];
for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
void work()
{
for(int i=;i<=n;i++)rk[i]=s[i],tp[i]=i;
Rsort();
for(int k=;k<=n;k<<=)
{
int num=;
for(int i=n-k+;i<=n;i++)tp[++num]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++num]=sa[i]-k;
Rsort();
memcpy(tp,rk,sizeof rk);//swap(rk,tp);
rk[sa[]]=; num=;
for(int i=;i<=n;i++)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[sa[i]+k]==tp[sa[i-]+k])?num:++num;
if(num==n)break;
m=num;
}
}
void get()
{
int k=; ht[]=;
for(int i=;i<=n;i++)
{
if(rk[i]==)continue;
if(k)k--; int j=sa[rk[i]-];
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
ht[rk[i]]=k;
}
}
int main()
{
int K;
while()
{
scanf("%d",&K); if(!K)return ;
scanf("%s",a+); int l1=strlen(a+);
scanf("%s",b+); int l2=strlen(b+);
n=l1+l2+;
for(int i=;i<=l1;i++)s[i]=a[i]; s[l1+]='z'+;
for(int i=;i<=l2;i++)s[l1++i]=b[i];
m=; work(); get();
ll ans=;
ll sum=; top=;
for(int i=,y;i<=n;i++)
{
cnt[i]=;
if(ht[i]<K){top=; sum=; continue;}//min<K
while(ht[i]<ht[y=sta[top]]&&top)
{
sum-=(ll)cnt[y]*(ht[y]-K+);
sum+=(ll)cnt[y]*(ht[i]-K+);//
top--; cnt[i]+=cnt[y];
}
sta[++top]=i;
if(sa[i-]>l1+)sum+=ht[i]-K+,cnt[i]++;//cal(i-1):ht[i]
if(sa[i]<=l1)ans+=sum;
}
sum=; top=;
for(int i=,y;i<=n;i++)
{
cnt[i]=;
if(ht[i]<K){top=; sum=; continue;}//min<K
while(ht[i]<ht[y=sta[top]]&&top)
{
sum-=(ll)cnt[y]*(ht[y]-K+);
sum+=(ll)cnt[y]*(ht[i]-K+);
top--; cnt[i]+=cnt[y];
}
sta[++top]=i;
if(sa[i-]<=l1)sum+=ht[i]-K+,cnt[i]++;
if(sa[i]>l1+)ans+=sum;
}
printf("%lld\n",ans);
}
return ;
}

poj 3415 Common Substrings —— 后缀数组+单调栈的更多相关文章

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

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

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

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

  3. poj 3415 Common Substrings - 后缀数组 - 二分答案 - 单调栈

    题目传送门 传送点I 传送点II 题目大意 给定串$A, B$,求$A$和$B$长度大于等于$k$的公共子串的数量. 根据常用套路,用一个奇怪的字符把$A$,$B$连接起来,然后二分答案,然后按mid ...

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

  5. POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数

    题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS   Memory Limit: 65536K ...

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

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

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

  8. poj 3415 Common Substrings【SA+单调栈】

    把两个串中间加一个未出现字符接起来,然后求SA 然后把贡献统计分为两部分,在排序后的后缀里,属于串2的后缀和排在他前面属于串1的后缀的贡献和属于串1的后缀和排在他前面属于串2的后缀的贡献 两部分分别作 ...

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

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

随机推荐

  1. HTML中Select的使用详解

    <html><head><SCRIPT LANGUAGE="JavaScript"><!--//oSelect 列表的底部添加了一个新选项 ...

  2. 【demo练习三】:图片水平滚动、点击按钮变更图片动画

    要求:四张图片水平滚动,每隔5秒进行一次循环,点击按钮随机变更图片. XAML前台代码: <Window x:Class="图片滚动.MainWindow" xmlns=&q ...

  3. Spring 简单描述

    摘抄自知乎 建议不要硬着头皮看spring代码,本身的代码800多m,就是不上班开始看也不知道什么时候看完.如果想学学ioc,控制反转这些建议看看jodd项目,比较简练,但是我仍然不建议过多的看这些框 ...

  4. Android进程的生命周期

    Android系统想要永久的保留一个应用进程差点儿是不可能的.所以系统就须要不断的释放老的或者不太重要的进程以便腾出足够的内存空间来执行新的或者更重要的进程,那么系统怎样决定哪个进程应该保留哪个应该杀 ...

  5. 一步步玩pcDuino3--mmc下的裸机流水灯

            第一部分是玩pcduino3下的裸机.这个过程能够让我们更好的理解嵌入式系统,熟悉我们使用的这个平台.         首先介绍下开发环境: 虚拟机:VMware® Workstati ...

  6. 深刻理解render 和 redirect_to

    深刻理解render 和 redirect_to http://www.blogjava.net/fl1429/archive/2009/03/12/259403.html 由于最近老是在表单提交后出 ...

  7. mysql优化之 EXPLAIN(一)

    数据库优化最常用的命令就是用explain查看一下写的sql是否用到了索引: 如: (root@localhost) [akapp]>explain select * from sc_activ ...

  8. <关于J2EE环境的搭建>在Fedora21下的Tomcat,Mysql,jdk以及Intellij的搭建过程

    题外话:一开始很不情愿写这种没有技术含量的博文,但是网上对于fedora21下的整个J2EE环境的搭建过程的文章实在是少之又少,那我就破个例吧:-p (一)JDK的下载及环境变量的设置 如果你对JDK ...

  9. POJ2278 DNA Sequence —— AC自动机 + 矩阵优化

    题目链接:https://vjudge.net/problem/POJ-2778 DNA Sequence Time Limit: 1000MS   Memory Limit: 65536K Tota ...

  10. smokeping 微信报警配置

    1. 准备alert脚本,用来调用微信脚本 #!/bin/bash alertname=$ target=$ losspattern=$ rtt=$ smokename="hq_to_idc ...