列表

详情


NC20206. [JSOI2013]编程作业

描述

考虑到如下的两段代码,很容易发现他们其实是一样的。 
代码1 
int i, j;
i = 3;
j = i + 1; 
代码2 
int a, i; 
a = 3; 
i = a + 1; 
这是因为这两段代码之间唯一的差异,只是他们更换了一下变量名,比如第一段代码中的i变成了第二段的a,第一段的j变成了第二段的i。而其他的常量, 例如3,1或者其他的关键字和运算符,比如 int,+和;。都是没有发生变化的。  不过注意到如下的代码片段,我们并不能简单认为这是一样的,因为这不是 一个简单的替换,而是可以导致不同运算结果的。 
代码3 
a = 3; 
b = 3; 
代码4 
c = 3; 
 c = 3;  
 为了简化问题,我们用大写字母来表示所有的关键字、常量等非变量符合。 假如我们采用如下的替换表  
那么最开始给出的两段雷同代码就可以分别写成 AiBjCiDECjDiFGC 以及 AaBiCaDECiDaFGC。或者简单的说,我们认为这两段代码是一样的。
现在请写一个程序,处理若干这样的代码雷同检测问题:给一个完整代码以及一个较短的代码片段,请求出,这个代码片段在完整代码中一共出现了多少次 (代码片段出现的位置可以重叠)。 
为了简单起见,我们认为程序中只会至多出现 a~z 这 26 个变量,同时也至多只有A~Z这26个非变量符号。

输入描述

第一行包含一个整数 Q表示此数据中一共包含 Q个询问。
接下来 2Q行,每两行为一个询问。
每个询问中的第一行包含一个字符串 S,表示完整代码,
第二行包含一个字符串 T,表示需要检测出现次数的代码片段。

输出描述

一共输出 Q行,每行一个整数,表示对应代码片段的出现次数。

示例1

输入:

3
AiBjCiDECjDiFGC
AaBiCaDECiDaFGC
cDEcDEbDE
aDEbDE
ccddef
aab

输出:

1
1
2

说明:

【样例说明】
前两个样例均为题目中所举例的代码段。第三个样例中,在完整代码 S中与
代码片段T 一样的片段为:ccd和dde

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 31ms, 内存消耗: 13296K, 提交时间: 2020-07-14 22:55:06

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
struct KMP
{
    int n, next[maxn], t[maxn];
    bool cmp(int a, int b, int p){return a==b or a>p and b>p;};
    void build(int *r, int len)
    {
        int i, j=0;
        n=len;
        for(i=1;i<=len;i++)t[i]=r[i];  t[len+1]=0;
        for(i=2;i<=len;i++)
        {
            for(;j and !cmp(t[j+1],t[i],j);j=next[j]);
            next[i] = cmp(t[j+1],t[i],j)?++j:0;
        }
    }
    int move(int pos, int x)
    {
        for(;pos and !cmp(t[pos+1],x,pos);pos=next[pos]);
        return cmp(t[pos+1],x,0) ? pos+1 : 0;
    }
}kmp;
ll last[maxn], pre[maxn];
int S[maxn], T[maxn];
char s[maxn], t[maxn];
int main()
{
    ll Q=read();
    while(Q--)
    {
        ll i, j, n, m;
        scanf("%s%s",s+1,t+1);
        n=strlen(s+1);
        m=strlen(t+1);
        rep(i,0,300)last[i]=-1;
        rep(i,1,n)
        {
            pre[i]=last[s[i]];
            last[s[i]]=i;
            if(islower(s[i]))S[i] = i-pre[i];
            else S[i]=-s[i];
        }
        rep(i,0,300)last[i]=-1;
        rep(i,1,m)
        {
            pre[i]=last[t[i]];
            last[t[i]]=i;
            if(islower(t[i]))T[i] = i-pre[i];
            else T[i]=-t[i];
        }
        // de("debug1");
        kmp.build(T,m);
        ll ans=0, p=0;
        rep(i,1,n)
        {
            p = kmp.move(p,S[i]);
            if(p==m)ans++, p=kmp.next[p];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 75ms, 内存消耗: 17176K, 提交时间: 2022-11-29 14:11:23

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define ft first
#define sd second
#define pii pair<int,int>
#define pll pair<ll,ll>
using namespace std;
 
const int maxn=2e6+10;
int nt[maxn],pre[maxn],pos2[maxn],pos1[maxn];
char s1[maxn],s2[maxn];
 
void getpre(char s[],int pos[],int n)
{
    for(int i=0;i<=128;i++) pre[i]=-1;
    for(int i=0;i<n;i++){
        if(s[i]>='A'&&s[i]<='Z') {pos[i]=s[i]-'A'+1;continue;}
        if(pre[s[i]-'a']==-1) pos[i]=-1;
        else pos[i]=i-pre[s[i]-'a']+30;
        pre[s[i]-'a']=i;
    }
}
 
void getnt(int s[],int n)
{
    int i=0,j=-1;
    nt[0]=-1;
    while(i<n){
        if(j==-1||(j+30<s[i]?s[j]==-1:s[i]==s[j])) i++,j++,nt[i]=j;
        else j=nt[j];
    }
}
 
int kmp(int s[],int p[],int n,int m)
{
    getnt(p,m);
    int i=0,j=0,ans=0;
    while(i<n){
        if(j==-1||(j+30<s[i]?p[j]==-1:s[i]==p[j])) i++,j++;
        else j=nt[j];
        if(j==m) ans++;
    }
    return ans;
}
 
int main()
{
    int t;
    cin>>t;
    while(t--){
        memset(pos1,0,sizeof(pos1));
        memset(pos2,0,sizeof(pos2));
        cin>>s1>>s2;
        int n=strlen(s1),m=strlen(s2);
        getpre(s1,pos1,n);
        getpre(s2,pos2,m);
 
        printf("%d\n",kmp(pos1,pos2,n,m));
    }
    return 0;
}

C++(clang++11) 解法, 执行用时: 19ms, 内存消耗: 5368K, 提交时间: 2020-10-30 00:56:59

#include<bits/stdc++.h>
using namespace std;
const int M=1e6+9;
int n,m;
int a[M],b[M],f[M],last[209];
char s[M],t[M];
bool cmp(int x,int y,int newletter){
	return x==y||(x>=newletter&&y>=newletter);
}
void work(int ans=0){
	scanf("%s%s",s+1,t+1);
	m=strlen(t+1);a[m+1]=0;
	n=strlen(s+1);b[n+1]=0;
	for(int i=1,j=0;i<=m;f[++i]=++j){
		if(t[i]>'Z'){a[i]=i-last[t[i]];last[t[i]]=i;}
		else a[i]=-t[i];
		while(j&&!cmp(a[i],a[j],j))j=f[j];
	}
	memset(last,0,sizeof(last));
	for(int i=1,j=1;i<=n;++i,++j){
		if(s[i]>'Z'){b[i]=i-last[s[i]];last[s[i]]=i;}
		else b[i]=-s[i];
		while(j&&!cmp(b[i],a[j],j))j=f[j];
		if(j==m)ans++;
	}
	memset(last,0,sizeof(last));
	printf("%d\n",ans);
}
int main(){
	int T;scanf("%d",&T);
	while(T--)work();
	return 0;
}

上一题