【POJ1743】Musical Theme & SA的模板和学习笔记

本文介绍了一种利用后缀数组和最长公共前缀(LCP)解决问题的方法,通过差分和二分查找技术确定两个不相交区间内的最长相同子串长度。

题意

可以修改一段区间的值 求两端不相交区间相同的最长长度。

思路

可以修改值的话 直接差分解决
求最长长度可以二分一个答案k,然后将height小于k的挖掉。 产生多个区间找到区间,那么区间内的LCP都符合要求,区间与区间不符合,因为两个后缀的LCP等于对应rank之间height的最小值。
怎么保证不相交呢?
找到区间内最大和最小的SA 判断Max-Min是否大于k 不能等于因为是差分数组如果等于k的话会重复。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=40000+5;
int n,a[maxn],b[maxn];
int r[maxn],y[maxn],sa[maxn],rank[maxn],height[maxn],c[maxn];
//r表示排名 y表示第二关键字排序 sa为后缀数组 rank表示第i个后缀的排名 height表示排i的后缀和前一个的最大公共前缀 
int pos[maxn];
void getsa(int *r,int *y,int m,int n)
{
    for(int i=0; i<=m; i++) c[i]=0;//初始化桶 
    for(int i=1; i<=n; i++) c[r[i]=a[i]]++;//压入同中,记录初始r 
    for(int i=1; i<=m; i++) c[i]+=c[i-1];//记录比i小的有多少 
    for(int i=n; i>=1; i--) sa[c[r[i]]--]=i;//初始化sa,可能有一样的 
    for(int len=1; len<=n; len<<=1)
    {
        int p=0;
        for(int i=n; i>=n-len+1; i--) y[++p]=i;//最后的几个长度不够有第二关键字,所以第二关键字最小 
        for(int i=1; i<=n; i++) if(sa[i]>len) y[++p]=sa[i]-len;//因为之前一次已经排好了一遍,所以直接按顺序找第二关键字对应的第一关键字 
        for(int i=0; i<=m; i++) c[i]=0;//初始化 
        for(int i=1; i<=n; i++) c[r[y[i]]]++;//将第一关键字压入桶中 
        for(int i=1; i<=m; i++) c[i]+=c[i-1];//同开始 
        for(int i=n; i>=1; i--) sa[c[r[y[i]]]--]=y[i];//算sa 
        swap(r,y);
        p=2; r[sa[1]]=1;//重新求排名第一关键字 
        for(int i=2; i<=n; i++)
        {
            if(y[sa[i]]==y[sa[i-1]] && y[sa[i]+len]==y[sa[i-1]+len]) r[sa[i]]=p-1;
            else r[sa[i]]=p++;
        }
        if(p>n) return;//所有的n个都有对应的sa了 不重复,完成。 
        m=p;
    }
}
void getheight()
{
    for(int i=1; i<=n; i++) rank[sa[i]]=i;
    for(int i=1,k=0; i<=n; i++)
    {
        if(k>0) k--;
        int t=sa[rank[i]-1];
        while(a[i+k]==a[t+k]) k++;
        height[rank[i]]=k;
    }
}
void init()
{
    memset(sa,0,sizeof(sa));
    memset(height,0,sizeof(height));
    memset(b,0,sizeof(b));
    memset(a,0,sizeof(a));
    memset(r,0,sizeof(r));
    memset(y,0,sizeof(y));
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&b[i]); a[i]=b[i]-b[i-1];
    }
    for(int i=1; i<=n; i++) a[i]+=88;
}
bool can(int x)
{
    pos[0]=0;
    for(int i=1; i<=n; i++)
    {
        if(height[i]<x) pos[++pos[0]]=i;
    }
    if(pos[pos[0]]<n) pos[++pos[0]]=n+1;
    for(int i=2; i<=pos[0]; i++)
    {
        int minn=0x7ffffff,maxx=0;
        for(int j=pos[i-1]+1; j<pos[i]; j++)
        {
            minn=min(minn,min(sa[j],sa[j-1])); maxx=max(maxx,max(sa[j-1],sa[j]));
            if(maxx-minn>x) return true;//因为是差分所以要用大于x  
        } 
    }
    return false;
}
int solve()
{
    int l=0,r=n;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(can(mid)) l=mid;
        else r=mid-1;
    } l++;
    if(l<5) l=0;
    return l;
}
int main()
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    scanf("%d",&n);
        init();
        getsa(r,y,177,n); getheight();
        for(int i=1; i<=n; i++)
        {
            cout<<height[i]<<endl;
        }
        printf("%d\n",solve());
    return 0;
} 

学习笔记

SA的求解代码注释的比较易懂了 实在不懂可以到网上找点图看看

height数组的求解方法

height数组的求解需要用到一个性质
令h[i]=height[rank[i]]
那么就有 h[i]>=h[i1]1h[i]>=h[i−1]−1
证明 i前面的一个后缀是i-1,i比i-1少一个字符
令 k=sa[rank[i-1]-1] 即排在i-1前的一个后缀。
那么k+1就比k要少一个字符
设k与i-1的LCP为[l,r] 很显然的是因为k+1只比k少一个 i只比i-1少一个那么 k+1与i至少有[l+1,r]的是完全相同的
那么LCP(k+1,i)>=LCP(k,i1)1h[i1]1LCP(k+1,i)>=LCP(k,i−1)−1即h[i−1]−1
而我们又知道两个后缀的LCP等于对应rank之间height的最小值。
所以h[i]>=LCP(k+1,i)>=LCP(k,i1)1h[i1]1h[i]>=LCP(k+1,i)>=LCP(k,i−1)−1即h[i−1]−1
代码上边有

常用技巧

  1. 二分一个值把比这个值小的height去掉剩下一段段区间。
  2. 将height排序然后一个一个的将区间拆成两半。
  3. 求长度为L的字串出现几次的话找到L,2*L,3*L,4*L这些点最少两次的话最少要覆盖两个点,可以枚举每对点,比如说是L,2*L求以L为开头的后缀和以2*L为开头的后缀的LCP长度len1 和以2*L为开头前缀和L为开头的前缀的最长公共后缀(LCS?) 长度len2 len1+len2就是以L为循环节的最长长度。
    有时间补上图
内容概要:本文设计了一种基于PLC的全自动洗衣机控制系统内容概要:本文设计了一种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制类项目开发参考一定PLC基础知识。; 阅读梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中类似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值