单词(word)

【问题描述】
给定一个特定的序列,这个序列由数个单词组成,现在我们知道一个加密序列,已知加
密序列一定是特定序列的一部分,找出这个加密序列在特定序列中的第一次出现的位置。
注意:加密是以替换的形式,也就是说,加密序列与特定序列中的单词必须一一对应。
【输入格式】
第一行包括数个单词,单词末尾以$作结,每个单词间相隔一个空格,表示特定序列,$不被
算作单词。
第二行格式相同,表示加密序列。
注意:每一个序列的字母数不会超过 10^6,
【输出格式】
输出加密序列在特定序列中出现的第一个单词的位置,保证答案一定存在。
【输入输出样例】
输入
a a a b c d a b c $
x y $
输出
3
输入
a b c x c z z a b c $
prvi dr prvi tr tr x $
输出
3

输出
3
输入
xyz abc abc xyz $
abc abc $
输出
2

 

【数据说明】
对于 50%的数据,N≤1000。
对于 100%的数据,2≤N≤300000。

 

思路:

这题就是让我们在一个长串找一个相似的子结构,我们发现,虽然字符是不一样的,但是在同一个串中同一个字符的距离间隔应该是相同的,那么我们用距离来构造匹配串

以下面为例:

a b c x c z z a b c $
prvi dr prvi tr tr x $

生成串为:

0 0 0 0 2 0 1 7 7 5
0 0 2 0 1 0

然后我们会发现:

 0 0 2 0 1 7

0 0 2 0 1 0

匹配了???

那是因为主串值可能被主串之前的值影响

那么有以下两点就是显然的了

1.本次的主串值在本次匹配中第一次出现,所以如果匹配,2号串的该位为0

2.因为是第一次出现,所以1号串的该位上代表的距离应该超出本次匹配串的长度

所以有:

while(j&&(s1[i+1]!=s2[j+1]&&(s2[j+1]>0||j-s1[i+1]>=0))) j=kmp[j];

if(s1[i+1]==s2[j+1]||(s2[j+1]<=0&&j-s1[i+1]<0)) j++;

然后就可以上代码了

#include <cstdio>
#include <cstring>

using namespace std;

#define R register
#define GC getchar()
#define mod1 1000007
#define ll long long
#define MAXN 1000000+5
#define mod2 10000000009

ll h[mod1+5];
int cnt1=0,cnt2=0;
int s1[MAXN],s2[MAXN];
int kmp[MAXN],pl[mod1+5];

inline void pre();
inline void KMP();
inline char clear();
inline void KMP_pre();

int main()
{
    pre();
    KMP_pre();
    KMP();
    return 0;
}

inline char clear()
{
    char c=GC;
    while (c<'a'||c>'z') c=GC;
    return c;
}

inline void pre()
{
    freopen("word.in","r",stdin);
    freopen("word.out","w",stdout);
    R char c=clear();
    while(c!='$')
    {
        R ll x=0;
        while(c>='a'&&c<='z') x=(x*37+(c-'a'+1))%mod2,c=GC;
        R ll tx=x%mod1;cnt1++;
        while(h[tx])
        {
            if(h[tx]==x)
            {
                s1[cnt1]=cnt1-pl[tx]; //记录长度差
                pl[tx]=cnt1;break; // 记录本次地址
            }
            tx=(tx+1)%mod1; //处理哈希冲突
        }
        if(!h[tx])
        {
            s1[cnt1]=0;
            h[tx]=x,pl[tx]=cnt1;
        }
        c=GC;
    }
    memset(h,0,sizeof(h));
    memset(pl,0,sizeof(pl));
    c=clear();
    while(c!='$')
    {
        R ll x=0;
        while(c>='a'&&c<='z') x=(x*37+(c-'a'+1))%mod2,c=GC;
        R ll tx=x%mod1;cnt2++;
        while(h[tx])
        {
            if(h[tx]==x)
            {
                s2[cnt2]=cnt2-pl[tx];//同上
                pl[tx]=cnt2;break;
            }
            tx=(tx+1)%mod1;
        }
        if(!h[tx])
        {
            s2[cnt2]=0;
            h[tx]=x,pl[tx]=cnt2;
        }
        c=GC;
    }
    
    //for(R int i=1;i<=cnt1;i++) printf("%d ",s1[i]);
    //printf("\n");
    //for(R int i=1;i<=cnt2;i++) printf("%d ",s2[i]);
    //printf("\n");
}

inline void KMP_pre()
{
    kmp[1]=0;
    for(R int i=1,j=0;i<cnt2;i++)
    {
        while(j&&s2[i+1]!=s2[j+1]) j=kmp[j];
        if(s2[i+1]==s2[j+1]) j++;
        kmp[i+1]=j;
    }
}

inline void KMP()
{
    for(R int i=0,j=0;i<cnt1;i++)
    {
        while(j&&(s1[i+1]!=s2[j+1]&&(s2[j+1]>0||j-s1[i+1]>=0))) j=kmp[j];
        /*1.本次的主串值在本次匹配中第一次出现,所以如果匹配,2号串的该位为0
        2.因为是第一次出现,所以1号串的该位上代表的距离应该超出本次匹配串的长度*/
        if(s1[i+1]==s2[j+1]||(s2[j+1]<=0&&j-s1[i+1]<0)) j++;
        if(j==cnt2) {printf("%d\n",i+1-cnt2+1);return;}
    }
    putchar('0'),putchar('\n');
    return;
}

 

转载于:https://www.cnblogs.com/000226wrp/p/11347856.html

### 回答1: 美国当代英语语料库最常用的5000单词是指在美国英语使用中最常出现的5000个词汇。这些词汇涵盖了各个领域,包括日常生活、工作、学习等。通过对这些最常用的单词进行学习,可以大大提高我们的英语表达能力和听力水平。 如果想要下载这些常用单词,在网上可以找到很多资源,其中比较常见的是Word网盘。只需要搜索“美国当代英语语料库最常用的5000单词Word网盘下载”,就可以找到很多相关的链接和资源。 学习这些常用单词需要一定的时间和精力,但也会给我们带来很大的收益。在学习过程中,可以结合各种练习方法,如背单词、阅读英文文章和听力练习等,这样不仅可以加深记忆,还可以提高英语运用能力。总之,如果想要提高自己的英语水平,学习这些最常用的单词一个不错的选择。 ### 回答2: 美国当代英语语料库最常用的5000单词是指在美国当代英语中最常使用的5000个单词。这个单词列表是根据大量的语料库数据和语言统计学分析得出的。这个列表在学习英语的人群中非常受欢迎,因为这些是最常使用的单词,掌握了这些单词可以有效地提高英语能力,帮助人们更好地沟通和交流。 如果您需要下载这个5000个单词的列表,可以在网上搜索“美国当代英语语料库最常用的5000单词下载”,会有很多网站提供下载。其中,Word网盘是比较常用的一个云盘工具,可以在网盘上上传和下载文件,操作简单方便。只需要在Word网盘中搜索“美国当代英语语料库最常用的5000单词下载”,相信会有很多人分享这个资源。 最后,需要提醒大家的是,在学习英语的过程中,单词是基础,但不要只局限于背单词,要注重单词的使用和语境,多读英文文章,加强口语练习,才能真正提高英语能力。 ### 回答3: 美国当代英语语料库中最常用的5000单词是很有用的资源,可以帮助我们更好地了解和掌握英语语言。这些单词是使用频率最高的单词,覆盖了日常生活和学术领域中所需的词汇量。 通过使用这些常用单词,我们可以提高我们的词汇量,因为这些单词在口语和书面语中都使用频繁。我们可以构建自己的语句、表达自己的意见,同时可以听懂和阅读英语材料。 此外,这些单词也可以帮助我们更好地理解英语的语法和用法。因为这些单词经常与其他词汇组合使用,掌握这些单词的意义和用法可以让我们更加熟悉英语语言。 下载美国当代英语语料库中最常用的5000单词是非常简单的,只需在网盘上搜索相关资源即可。结合词典和其他学习资源,我们可以充分利用这个资源,提高自己的英语水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值