前言
同样,见“energy”一题
题目
Sample Input 1
aaaa
aaaa
Sample Output 1
4
Sample Input 2
a*a
aaaaaa
Sample Output 2
6
Sample Input 3
*a*b*c*
abacabadabacaba
Sample Output 3
15
【数据范围】
对于 30%的数据,M<=20;
对于 80%的测试点,M<=200;
对于 100%的测试点,1<=N<=100,1<=M<=100000。
分析
太掉以轻心了...打了个代码,过了样例以为80分到手就没管了,居然只有9分,我我我我我....
考试思路:
字符‘ * ’变成什么都可以,于是不用管,只要a中剩下的字符在b中顺次出现就好了
所以枚举b的所有“循环同构串”,检验a中字符在b中是否顺次全部出现
感觉非常没毛病qwq... ...搞不懂哪里出了问题,有待继续探讨
考试只有9分的奇怪代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5;
char a[MAXN+5],b[MAXN+5],tmp[MAXN+5];
int n,m,ans,len;
bool Check(int id)
{
int cnt=1;
for(int i=id;i<=id+m-1;i++)
{
if(b[i]==tmp[cnt])
cnt++;
}
if(cnt==len+1)
return true;
return false;
}
int main()
{
//freopen("journey.in","r",stdin);
//freopen("journey.out","w",stdout);
scanf("%s%s",a+1,b+1);
n=strlen(a+1);
m=strlen(b+1);
for(int i=1;i<=m;i++)
b[i+m]=b[i];
for(int i=1;i<=n;i++)
if(a[i]!='*')
tmp[++len]=a[i];
for(int i=1;i<=m;i++)//字符串开头字母位置i
if(Check(i))
ans++;
printf("%d",ans);
return 0;
}
/*
至少保证80%的分到手(M<=200)
'*'可以匹配任意多个字符,[包括0个]
*/
AC代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e5;
ll hash[MAXN+5],h[MAXN+5],len[MAXN+5],g[MAXN+5];
int f[2*MAXN+5][100];
char a[MAXN+5],b[2*MAXN+5];
ll n,m,cnt,c,ans;
int main()
{
//freopen("journey.in","r",stdin);
//freopen("journey.out","w",stdout);
scanf("%s%s",a+1,b+1);
n=strlen(a+1);
m=strlen(b+1);
hash[0]=1;
for(int i=1;i<=n;i++)
hash[i]=hash[i-1]*13331;
int tmp=0;
for(int i=1;i<=n;i++)
{
if(a[i]=='*')
{
if(i>1&&a[i-1]!='*')
{
h[++cnt]=tmp;//每一段的hash值
len[cnt]=c;//每一段的长度
tmp=c=0;
}
}
else
tmp+=(a[i]-'a'+1)*hash[c++];
}
if(a[n]!='*')
h[++cnt]=tmp,len[cnt]=c;
for(int i=1;i<=m;i++)
b[i+m]=b[i];
if(!cnt)//都是'*'
{
printf("%lld",m);
return 0;
}
for(int i=1;i<=cnt;i++)//预处理
f[m*2+1][i]=f[m*2+2][i]=m*2+1;
for(int i=m*2;i;i--)//处理b串的hash值
{
memset(g,-1,sizeof(g));
g[0]=0;
for(int j=0;j<n;j++)
if(i+j<=2*m)//是一个子串
g[j+1]=g[j]+(b[i+j]-'a'+1)*hash[j];
for(int j=1;j<=cnt;j++)
{
f[i][j]=f[i+1][j];
if(g[len[j]]==h[j])//a,b有相同子串
f[i][j]=i+len[j]-1;
}
}
int j,k,w;
for(int i=1;i<=m;i++)
{
bool flag=true;
for(j=n;j&&a[j]!='*';j--)
if(a[j]!=b[i+m-1-(n-j)])//在b中找一个合法的起始位置
{
flag=false;
break;
}
if(!flag||j==0&&n!=m)
continue;
for(k=1,w=i;k<=cnt-(a[n]!='*');k++)//k:段数,w:位置
{
if(k==1&&a[1]!='*'&&f[i][k]+1!=i+len[1])
break;
w=f[w][k]+1;
}
if(k>cnt-(a[n]!='*')&&w<=i+m-(n-j))
ans++;
}
printf("%lld",ans);
return 0;
}