hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq

hdu 4691 最长的共同前缀 后缀数组 +lcp+rmq

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

http://acm.hdu.edu.cn/showproblem.php?

pid=4691

去年夏天,更多的学校的种族称号。当时,没有后缀数组

今天将是,事实上,自己的后缀阵列组合rmq或到,但是,题意理解的一个问题,再折腾了很长时间,,,,

此处简单解释下题目例子吧,希望对读者有帮助  以最后一组数据为例

myxophytamyxopodnabnabbednabbingnabit

6

0 9

9 16

16 19

19 25

25 32

32 37

前两行不解释,题目叙述非常清楚

从第三行,0 9 指的是第一个字符串是从第一行的字符串的0-9 左闭右开,

下面5行同样

继续看题目的正文叙述的例子

那么压缩之后的第一个就是“0空格以及前9个字符外加一个换行”一共12个。下面几行相同的算法

注意假设公共前缀长度是24,那么按两个单元存储,这就是我写的Weishu函数的作用

上代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>

using namespace std;

const int MAXN =100000+20;

int n,k;//n=strlen(s);
int Rank[MAXN],tmp[MAXN],d[MAXN],st[MAXN][20],lcp[MAXN],sa[MAXN];
char s[MAXN];

/*使用Rank对sa排序*/
bool cmpSa(int i, int j)
{
    if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
    else
    {   /*以下的Rank[t],已经是以t开头长度小于等于k/2的。
        sa[i]的名次,仅仅是以i开头的后缀,而长度不同*/
        int ri = i+k <=n? Rank[i+k]:-1;
        int rj = j+k <= n ? Rank[j+k]:-1;
        return ri <rj;
    }
}

/*计算SA*/
void consa(char *s, int *sa)
{
    for(int i=0;i<=n;i++){
        sa[i]=i;Rank[i] = i < n?s[i]:-1;
    }

    for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1開始,由于0*2=0*/
    {
        sort(sa,sa+n+1,cmpSa);
        tmp[sa[0]] = 0; /*此时tmp仅仅是暂存rank*/
        for(int i=1;i<=n;i++){
            tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
        }
        for(int i=0;i<=n;i++){
            Rank[i] = tmp[i];
        }
    }
}

void construct_lcp(char *s,int *sa,int *lcp)
{
    //n=strlen(s);
    for(int i=0; i<=n; i++)Rank[sa[i]]=i;

    int h=0;
    lcp[0]=0;
    for(int i=0;i<n;i++)
    {
        int j=sa[Rank[i]-1];

        if(h>0)h--;
        for(; j+h<n && i+h<n; h++)
        {
            if(s[j+h]!=s[i+h])break;
        }
        lcp[Rank[i]-1]=h;
    }
}

void InitRMQ(int nn)
{
    int i,j;
    for(d[0]=1,i=1;i<21;i++)d[i]=2*d[i-1];
    for(i=0;i<nn;i++)st[i][0]=lcp[i];
    ///////////////////////////////
   // for(int i=0;i<nn;i++)
   //{
  //      printf("%s i=%d sa=%d rank=%d lcp=%d\n",s+sa[i],i,sa[i],Rank[i],lcp[i]);
  //      printf("||||||||%s lcp[rank]=%d\n",s+i,lcp[Rank[i]]);
  //  }
    ////////////////////////////////

    int k=int( log(double(nn))/log(2.0)+1 );
    for(j=1;j<k;j++)
        for(i=0;i<nn;i++)
        {
            if(i+d[j-1]-1<nn)
            {
                st[i][j]=min(st[i][j-1],st[i+d[j-1]][j-1]);
            }
            else break;
        }
}

int weishu(int n)
{
    if(n<10)return 1;
    int ans=0;
    while(n)
    {
        n/=10;
        ans++;
    }
    return ans;
}

int main()
{
    //freopen("hdu4691.txt","r",stdin);
    long long ansb,ansa;
    int kk;
    while(~scanf("%s",s))
    {
        ansb=ansa=0;
        n=strlen(s);
        consa(s,sa);
        construct_lcp(s,sa,lcp);

        InitRMQ(n+1);
        int num,l,r,x,y;
        scanf("%d",&num);
        int last=0,lastlen=0;
        scanf("%d%d",&l,&r);
        ansb+=r-l+1;
        ansa+=r-l+3;
        lastlen=r-l;
        last=l;
        for(int i=1;i<num;i++)
        {
            scanf("%d%d",&l,&r);
            ansb+=r-l+1;
            ansa+=r-l;
            x=min(Rank[last],Rank[l]),y=max(Rank[last],Rank[l])-1;
            kk = int( log(double(y-x+1))/log(2.0) );
            int ret;
            if(l == last)ret=n-l;
            else ret=min(st[x][kk], st[y-d[kk]+1][kk]) ;
            ret=min(ret, min(lastlen,r-l));
            ansa =ansa-ret+weishu(ret)+2;
            last=l;
            lastlen=r-l;
        }
        printf("%I64d %I64d\n",ansb,ansa);
    }
    return 0;
}

再加一个rmq+后缀数组求最长公共前缀的模板吧

(事实上还没有測试,遇到题在測试)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>

using namespace std;

const int MAXN =100000+20;

int n,k;//n=strlen(s);
int Rank[MAXN],tmp[MAXN],d[MAXN],st[MAXN][20],lcp[MAXN],sa[MAXN];
char s[MAXN];

/*使用Rank对sa排序*/
bool cmpSa(int i, int j)
{
    if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
    else
    {   /*以下的Rank[t],已经是以t开头长度小于等于k/2的,
        sa[i]的名次。仅仅是以i开头的后缀,而长度不同*/
        int ri = i+k <=n? Rank[i+k]:-1;
        int rj = j+k <= n ? Rank[j+k]:-1;
        return ri <rj;
    }
}

/*计算SA*/
void consa(char *s, int *sa)
{
    for(int i=0;i<=n;i++){
        sa[i]=i;Rank[i] = i < n?s[i]:-1;
    }

    for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1開始。由于0*2=0*/
    {
        sort(sa,sa+n+1,cmpSa);
        tmp[sa[0]] = 0; /*此时tmp仅仅是暂存rank*/
        for(int i=1;i<=n;i++){
            tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
        }
        for(int i=0;i<=n;i++){
            Rank[i] = tmp[i];
        }
    }
}

void construct_lcp(char *s,int *sa,int *lcp)
{
    //n=strlen(s);
    for(int i=0; i<=n; i++)Rank[sa[i]]=i;

    int h=0;
    lcp[0]=0;
    for(int i=0;i<n;i++)
    {
        int j=sa[Rank[i]-1];

        if(h>0)h--;
        for(; j+h<n && i+h<n; h++)
        {
            if(s[j+h]!=s[i+h])break;
        }
        lcp[Rank[i]-1]=h;
    }
}

void InitRMQ(int nn)
{
    int i,j;
    for(d[0]=1,i=1;i<21;i++)d[i]=2*d[i-1];
    for(i=0;i<nn;i++)st[i][0]=lcp[i];
    int k=int( log(double(nn))/log(2.0)+1 );
    for(j=1;j<k;j++)
        for(i=0;i<nn;i++)
        {
            if(i+d[j-1]-1<nn)
            {
                st[i][j]=min(st[i][j-1],st[i+d[j-1]][j-1]);
            }
            else break;
        }
}

int ansLcp(int a, int b)
{
    int kk;
    if(a == b)return n-a;//n是整个字符串的长度
    x=min(Rank[a],Rank[b]),y=max(Rank[a],Rank[b])-1;
    kk = int( log(double(y-x+1))/log(2.0) );
    return min(st[x][kk], st[y-d[kk]+1][kk]) ;
}

int Query(int Q)//Q次询问
{
    int ans;
    for(int i=0;i<Q;i++)
    {
        scanf("%d%d",&a,&b);
        ans=ansLcp(a,b);
    }
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117450.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux 防火墙 命令_Linux高频命令汇总

    linux 防火墙 命令_Linux高频命令汇总原:https://blog.csdn.net/zhang123456456/article/details/781492061、firewalld的基本使用启动:systemctlstartfirewalld查看状态:systemctlstatusfirewalld停止:systemctldisablefirewalld禁用:systemctlstop…

    2022年4月19日
    39
  • 如何求逆矩阵_副对角线矩阵的逆矩阵怎么求

    如何求逆矩阵_副对角线矩阵的逆矩阵怎么求作为一只数学基础一般般的程序猿,有时候连怎么求逆矩阵都不记得,之前在wikiHow上看了一篇不错的讲解如何求3×3矩阵的逆矩阵的文章,特转载过来供大家查询以及自己备忘。当然这个功能在matlab里面非常容易实现,只要使用inv函数或A^-1即可,但是有时候参加个考试什么的还是要笔算的哈哈~假设有如下的3×3矩阵,第一步需要求出det(M),也就是矩阵M的行列式的值。行列式的值通常显示

    2022年8月21日
    14
  • zabbix添加snmp监控项_SNMP协议

    zabbix添加snmp监控项_SNMP协议目录一、SNMPTrap消息处理流程二、snmptt1、SNMPTrap、snmptt安装2、配置文件修改3、SNMPTrapFile文件创建4、监控项创建三、perl脚本 1、SNMPTrap安装2、从zabbix源码包中拷贝perl脚本到/usr/bin/目录下,并增加执行权限3、修改snmptrapd.conf配置4、修改zabbix配置 …

    2022年8月20日
    8
  • Python 数组操作_python中数组

    Python 数组操作_python中数组一.列表,元祖,:  1.元祖:      (1)创建:              tuple01=()#创建空元组                tuple01=(2,) #元组中只包含一个元素时,需要在元素后面添加逗号                tuple01=(‘joe’,’susan’,’black’,’monika’)      (2)将元组转换为…

    2022年8月13日
    12
  • 漏洞挖掘丨敏感信息泄露+IDOR+密码确认绕过=账户劫持

    漏洞挖掘丨敏感信息泄露+IDOR+密码确认绕过=账户劫持获得账户auth_token目标网站是一个工作招聘门户网站,测试保密原因暂且称其为redacted.com。一开始,我登录以应聘者身份去测试CSRF或某些存储型XSS,但没什么发现。接下来,我就想到了越权测试(IDOR),为此,我又创建了另外一个账号,两个账号一起可以测试如注册、登录、忘记密码等功能点的越权可能。创建账号前我开启了流量抓包想看看具体服务端的响应,注册开始时,网站会跳出一个提示,…

    2022年6月10日
    33
  • mybatis一级缓存和二级缓存失效_mybatis一级缓存和二级缓存

    mybatis一级缓存和二级缓存失效_mybatis一级缓存和二级缓存我们在上一篇文章(https://mp.weixin.qq.com/s/4Puee_pPCNArkgnFaYlIjg)介绍了MyBatis的一级缓存的作用,如何开启,一级缓存的本质是什么,一级缓存失效的原因是什么?MyBatis只有一级缓存吗?来找找答案吧!MyBatis二级缓存介绍上一篇文章中我们介绍到了MyBatis一级缓存其实就是SqlSession级别的缓存,什么…

    2026年1月29日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号