其他分享
首页 > 其他分享> > 答题卡

答题卡

作者:互联网

答题卡

题目大意

给定 \(n\) 个字符串,问有多少个二元组 \((i,j)\) 满足 字符串 \(i\) 的长度小于字符串 \(j\) 的长度,且字符串 \(j\) 能够通过下述两种操作变为字符串 \(i\) :

分析

首先对于这道题有一个非常显然的性质,一个成立的二元组必然满足一下条件:

之后可以考虑将所有的串全部倒序丢到一棵 \(trie\) 树上,预处理记录两个信息,一个是拥有这个前缀的字符串的数量,而是在这个前缀后有字母 \(x\) 的字符串数量。

之后进行匹配即可。

code

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=1e5+10;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w*=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w; 
}
int T,n,m;
int nex[M],pre_mode[M];
int pre[N];
char s[N],mode[M];
int last[256];
inline bool equal(int x,int y,int nowlen) { return x==y||x>nowlen&&y>nowlen; }
inline void work()
{
    scanf("%s%s",s+1,mode+1);
    n=strlen(s+1),m=strlen(mode+1);
    memset(last,0,sizeof(last));
    for(register int i=1;i<=m;i++){
        if(mode[i]>'Z') pre_mode[i]=i-last[mode[i]],last[mode[i]]=i;
        else pre_mode[i]=-mode[i];
    }
    memset(last,0,sizeof(last));
    for(register int i=1;i<=n;i++){
        if(s[i]>'Z') pre[i]=i-last[s[i]],last[s[i]]=i; 
        else pre[i]=-s[i];
 	}
    int j=nex[0]=nex[1]=0;
    for(register int i=2;i<=m;i++){
        while(j&&!equal(pre_mode[j+1],pre_mode[i],j)) j=nex[j];
        if(equal(pre_mode[j+1],pre_mode[i],j)) j++;
        nex[i]=j;
    }
    j=0;
    int ans=0;
    for(register int i=1;i<=n;i++){
        while(j&&!equal(pre_mode[j+1],pre[i],j)) j=nex[j];
        if(equal(pre_mode[j+1],pre[i],j)) j++;
        if(j==m) ans++,j=nex[j];
    }
    printf("%d\n",ans);
}
int main(){
    T=read();
    while (T--) work();
    return 0;
}

标签:pre,ch,last,int,答题卡,mode,字符串
来源: https://www.cnblogs.com/Defoliation-ldlh/p/15332678.html