[SDOI2008][luogu2463] Sandy的卡片 [kmp]

题面

传送门

思路

这道题里面有三个主要问题:

1.由“数值相等”变成了“加上一个整数以后数值相等”(减去等价于加负数)

2.由“最多匹配多少位(从第一位开始)”变成了从“任意一位开始匹配”

3.由“单文本串”变成了“多文本串”,而且是文本串内部自己匹配

我们按照难度顺序(3-1-2)来依次解决他们

问题三:多文本串

这个问题是最简单的,因为每个串长度不超过100,最多1000个串

所以,我们搞一个串出来成为模式串,然后用它去匹配剩下的串,结果取min就行了

问题一:数值加上整数相等

这个问题中我们要贯彻一个思想:取不变量

考虑一个序列,当它的每一个元素都增加了一定值以后,什么还是不变的?

没错,相邻元素(或者说任意两个元素)的差值

所以,本题中,我们只要把原来的序列变成长度小了1,元素为原来序列相邻两位之差的新序列来跑匹配,最后把答案加一就好了

问题二:可以从每一位开始匹配

这个问题,在解决了问题三以后也能迎刃而解:数据范围实在是太!小!了!

我们完全可以枚举模式串的开始位置,求出next数组,然后对于剩下的串每一个匹配一下,还能腾出一半的运行时间,大声喊出:

“zcy吊打集训队!”

Code:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
int a[1010][110],b[110];int N,n,m[1010],fail[110],ans=0,tans=inf,tmp;
int main(){
    N=read();int i,j,t1,t2,k,l;
    n=read();t1=read();for(i=0;i<n-1;i++) t2=read(),b[i]=t2-t1,t1=t2;
    b[n-1]=b[n]=b[n+1]=-inf;
    for(j=1;j<N;j++){
        m[j]=read();t1=read();
        for(i=0;i<m[j]-1;i++) t2=read(),a[j][i]=t2-t1,t1=t2;
        a[j][m[j]-1]=a[j][m[j]]=inf;
    }
    for(k=n-1;k>=1;k--){
        memset(fail,0,sizeof(fail));
        j=0;tans=inf;
        for(i=1;i<k;i++){
            while(j&&(b[i]!=b[j])) j=fail[j];
            j+=(b[i]==b[j]);fail[i+1]=j;
        }
        for(l=1;l<N;l++){
            j=0;tmp=0;
            for(i=0;i<m[l]-1;i++){
                while(j&&a[l][i]!=b[j]) j=fail[j];
                j+=(a[l][i]==b[j]);
                tmp=max(tmp,j);
                if(j==k) break;
            }
            tans=min(tans,tmp);
        }
        for(i=0;i<k-1;i++) b[i]=b[i+1];b[k]=-inf;
        ans=max(ans,tans);
    }
    printf("%d",ans+1);
}

原文地址:https://www.cnblogs.com/dedicatus545/p/8900736.html

时间: 2024-11-14 13:14:09

[SDOI2008][luogu2463] Sandy的卡片 [kmp]的相关文章

【SDOI2008】Sandy的卡片

题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型.相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串. Sandy的卡片数远远小于要求的N,于是Sue决定在Sandy的生日将自己的卡

luogu 2463 [SDOI2008]Sandy的卡片 kmp || 后缀数组 n个串的最长公共子串

题目链接 Description 给出\(n\)个序列.找出这\(n\)个序列的最长相同子串. 在这里,相同定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串. 思路 参考:hzwer. 法一:kmp 在第一个串中枚举答案串的开头位置,与其余\(n-1\)个串做\(kmp\). 法二:后缀数组 将\(n\)个串拼接起来.二分答案\(len\),将\(height\)分组,\(check\)是否有一组个数\(\geq len\)且落在\(n\)个不同的串中. 注意:\(n\)个串

BZOJ 4698: Sdoi2008 Sandy的卡片

4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 225  Solved: 95[Submit][Status][Discuss] Description Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积 攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型 ,首先必须要集够N张卡片,对

[Sdoi2008]Sandy的卡片

[Sdoi2008]Sandy的卡片 题目 Sandy和Sue的热衷于收集干脆面中的卡片.然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型.每一张卡片都由一些数字进行标记,第i张卡片的序列长度为Mi,要想兑换人物模型,首先必须要集够N张卡片,对于这N张卡片,如果他们都有一个相同的子串长度为k,则可以兑换一个等级为k的人物模型.相同的定义为:两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串.Sandy的卡片数远远小于要求的N,于是Sue决定

bzoj4698 / P2463 [SDOI2008]Sandy的卡片

P2463 [SDOI2008]Sandy的卡片 直接二分长度暴力匹配....... 跑的还挺快 (正解是后缀数组的样子) 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 void read(int &x){ 6 char c=getchar();x=0; 7 while(c<'0'||c>'9')c=getchar(); 8 w

[Luogu2463][SDOI2008]Sandy的卡片

BZOJ权限题qwq Luogu sol "两个子串长度相同且一个串的全部元素加上一个数就会变成另一个串" 其实就是差分一波以后完全相同 所以对输入的数据进行差分,同时记一下每一个位置是属于哪个串的. 记得在串与串中间加入一个没有出现的字符. 求出SA后二分答案\(mid\),问题变成:\(Height\)数组里是否存在一个大于等于\(mid\)的连续段使每个串都在里面出现过. 开桶记录.记一个\(id\)避免每次对桶的清空. code #include<cstdio> #

SDOI2008 Sandy的卡片( 后缀数组 )

求出后缀数组, 然后二分答案, 对height数组分组检验答案. 时间复杂度O(|S| log|S|) -------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; const

BZOJ4698 [SDOI2008] Sandy的卡片 - 后缀数组,二分

题意:求在N个串中都出现的最长子串 的长度 很容易想到二分转化为判定性问题.考虑长度M,我们按照长度M进行分组,每个组内进行答案验证,即检查组内是否有N个串的后缀都出现. 时间复杂度O(LlogM) 其实是个经典题. 二分时候记得初始化! 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 struct SA { 5 int str[2100005]; 6 int x[2100005],y[2100005],u[2100005],v[21

P2463 [SDOI2008]Sandy的卡片

题目链接 \(Click\) \(Here\) 真的好麻烦啊..事实证明,理解是理解,一定要认认真真把板子打牢,不然调锅的时候真的会很痛苦..(最好是八分钟能无脑把\(SA\)码对的程度\(QAQ\)) 这个题最开始我想的是\(RMQ\)遍历每一个子区间,但是意识到复杂度是\(O(N^2)\)然后就\(GG\)了.怎么说呢,后缀数组和二分似乎是很常见的组合(和莫队也是?),这个题只需要在\(height\)数组里二分\(lcp\)长度即可,\(check\)函数里面处理一下,要让区间内所有原串都