zoukankan      html  css  js  c++  java
  • CH1809 匹配统计

    题意

    描述

    阿轩在纸上写了两个字符串,分别记为A和B。利用在数据结构与算法课上学到的知识,他很容易地求出了“字符串A从任意位置开始的后缀子串”与“字符串B”匹配的长度。

    不过阿轩是一个勤学好问的同学,他向你提出了Q个问题:在每个问题中,他给定你一个整数x,请你告诉他有多少个位置,满足“字符串A从该位置开始的后缀子串”与B匹配的长度恰好为x。

    例如:A=aabcde,B=ab,则A有aabcde、abcde、bcde、cde、de、e这6个后缀子串,它们与B=ab的匹配长度分别是1、2、0、0、0、0。因此A有4个位置与B的匹配长度恰好为0,有1个位置的匹配长度恰好为1,有1个位置的匹配长度恰好为2。

    输入格式

    第一行三个整数N,M,Q,表示A串长度、B串长度、问题个数。

    第二行是字符串A,第三行是字符串B。

    接下来Q行每行1个整数x,表示一个问题。

    1<=N,M,Q,x<=200000.

    输出格式

    共Q行,依次表示每个问题的答案。

    样例输入

    6 2 5
    aabcde
    ab
    0
    1
    2
    3
    4

    样例输出

    4
    1
    1
    0
    0

    来源

    北京大学2015年数据结构与算法A期末考试

    分析

    参照wyboooo的题解。

    用KMP先求出以a[i]为结尾的前缀与b匹配的最长长度。

    比如 f[i] = j,就表示a[1~i]的后缀最多可以和b[1~j]匹配。但求出这个并不意味着以a[i]为开头的后缀可以和b恰好匹配j位(因为也许后面还可以匹配),但是可以肯定的是他至少可以匹配j位。我们很难求出恰好可以匹配x位的位置有多少,但是我们可以存至少可以匹配x位的位置的数目,结果用cnt[x] - cnt[x +1]就可以了。

    因此cnt[f[i]] ++就很显然了。

    由于我们之前求出的是最长长度,因此当a[1~i]可以最多和b[1~j]匹配时,也一定存在一个小于j的k使得a[1~i]和b[1~k]匹配,也就是一定能找到一个位置,至少匹配k位,但这个可能我们在之前没有加上过。而这个k恰好就等于nxt[j]。

    时间复杂度(O(N+M+Q))

    代码

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
    	rg T data=0,w=1;
    	rg char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') w=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))
    		data=data*10+ch-'0',ch=getchar();
    	return data*w;
    }
    template<class T>il T read(rg T&x){
    	return x=read<T>();
    }
    typedef long long LL;
    
    co int maxn=2e5+10;
    int n,m,q;
    char a[maxn],b[maxn];
    int nxt[maxn],f[maxn],cnt[maxn];
    void getnxt(){
    	nxt[1]=0;
    	for(int i=2,j=0;i<=m;++i){
    		while(j&&b[i]!=b[j+1]) j=nxt[j];
    		if(b[i]==b[j+1]) ++j;
    		nxt[i]=j;
    	}
    }
    int main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	read(n),read(m),read(q);
    	scanf("%s%s",a+1,b+1);
    	getnxt();
    	for(int i=1,j=0;i<=n;++i){
    		while(j&&a[i]!=b[j+1]) j=nxt[j];
    		if(a[i]==b[j+1]) ++j;
    		f[i]=j;
    	}
    	for(int i=1;i<=n;++i)
    		++cnt[f[i]];
    	for(int i=m;i>=1;--i)
    		cnt[nxt[i]]+=cnt[i];
    	for(int x;q--;){
    		read(x);
    		printf("%d
    ",cnt[x]-cnt[x+1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    python核心编程学习记录之基础知识
    VC++6.0出现no compile tool is associated with the extension.解决方法
    内存记号(Memory Trail)[自定义的名字] --调试方法
    Console 窗口
    C++ Builder创建和调用dll中的资源
    C++ builder 书籍推荐
    Qt书籍推荐
    消息队列数据结构
    Qt工程文件说明
    .obj : error LNK2001: unresolved external symbol "public: static unsigned long __stdcall ReadWrite::readData(void *)" (?readData@ReadWrite@@SGKPAX@Z)
  • 原文地址:https://www.cnblogs.com/autoint/p/10418656.html
Copyright © 2011-2022 走看看