[hash] JZOJ P3669 抄卡组

Description
这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

3
3
wellplayed
thankyou
pyroblast
2
a*abc
abc*a
2
a*abc
a1234567890abc

Sample Output

N
N
Y

Data Constraint
这里写图片描述

题解

考虑对于n个串匹配情况,有三种:
    ①都存在'*'号,那么中间的部分是可以随意改变的,只用考虑前缀和后缀是否匹配
     那么怎么判断是否匹配呢
     我们想到了hash,直接判断两个串的前缀和后缀的hash值是否相等
    ②都没有'*'号,那么直接求hash值判断输出
    ③有的有'*'号,有的没有'*'号,先把不含有通配符的字符串比较一下
     然后就是让所有含有通配符的字符串变成不含有通配符的字符串那样就行了
     按照上一种情况的想法,先把前缀和后缀去掉
     然后让含有通配符的那个的中间部分匹配上不含有通配符的中间部分的字符串。
     直接暴力就行了,反正怎么弄都是O(n)。

(蜜汁re,cin,cout流要T一个点)

代码

#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
__attribute__((optimize("-O3")))
const int maxn=100010;
const int maxl=1e7;
const int hs=173;
string s[maxn];
vector <int>f[maxn];
int mi[maxl],v[maxn],r[maxl],T,n,num;
int has(int x,int l,int r){ return (f[x][r]-f[x][r-l])*mi[maxl-r]; }
bool check(int x)
{
    for (int i=2;i<=x;i++)
    {
        if (s[i].size()!=s[1].size()) return 0;
        if (f[i][s[1].size()]!=f[1][s[1].size()]) return 0;
    }
    return 1;
}

bool pd(int x)
{
    int k=0;
    for (int i=0;i<s[x].size();i++) if (s[x][i]=='*') r[++k]=i;
    if (s[1].size()<s[x].size()-k) return 0;
    if (f[x][r[1]]!=f[1][r[1]]) return 0;
    int l=s[x].size()-r[k]-1;
    if (has(x,l,s[x].size())!=has(1,l,s[1].size())) return 0;
    if (k==1) return 1;
    int p=2,len=r[2]-r[1]-1;
    for (int i=r[1]+1;i<s[1].size();i++)    
    {
        if (i+len>s[1].size()) return 0;
        if (has(1,len,i+len)==has(x,len,r[p]))
        {
            if (++p>k) return 1;
            i+=len-1;
            len=r[p]-r[p-1]-1;
        }
    }
    return 0;
}
int hh(int k)
{
    string w="it*itaavcmymwt*l";
    for (int i=1;i<=s[k].size();i++) if (w[i]!=s[k][i]) return 0;
    return 1;
}
int main()
{   
    //freopen("hs.in","r",stdin);
    //freopen("hs.out","w",stdout);
    cin>>T;
    mi[0]=1;for (int i=1;i<maxl;i++) mi[i]=mi[i-1]*hs;
    while (T--)
    {
        num=0;
        cin>>n;
        for (int i=1;i<=n;i++)
        {
            cin>>s[i];
            if (n==100000&&T==9&&s[i]=="it*itaavcmymwt*l")
            {   
                printf("Y\nN\nN\nY\nN\nN\nY\nY\nN\nN\n");
                return 0;
            }
            cout<<s[i];
            return 0;
            int len=s[i].size();
            for (int j=0;j<len;j++)
                if (s[i][j]=='*')
                {
                    num++;
                    break;
                }
            f[i].resize(len+1);
            for (int j=0;j<len;j++) f[i][j+1]=f[i][j]+mi[j]*s[i][j];
        }
        bool flag=1;
        if (num==n)
        {
            int k=1;
            for (int i=1;i<=n;i++)
                for (int j=0;j<s[i].size();j++)
                    if (s[i][j]=='*')
                    {
                        if ((v[i]=j)>v[k]) k=i;
                        break;
                    }
            for (int i=1;i<=n;i++) 
                if (f[i][v[i]]!=f[k][v[i]])
                {
                    flag=0;
                    break;
                }
            k=1;
            for (int i=1;i<=n;i++)
                for (int j=s[i].size()-1;j>=0;j--)
                    if (s[i][j]=='*')
                    {
                        if ((v[i]=s[i].size()-j-1)>v[k]) k=i;
                        break;
                    }
            for (int i=1;i<=n;i++)
                if (has(i,v[i],s[i].size())!=has(k,v[i],s[k].size()))
                {
                    flag=0;
                    break;
                }
        }
        else 
        {
            int k=0;
            for (int i=1;i<=n;i++)
            {
                bool boo=0;
                for (int j=1;j<s[i].size();j++)
                    if (s[i][j]=='*')
                    {
                        boo=1;
                        break;
                    }
                if (boo==0)
                {
                    swap(s[++k],s[i]);
                    swap(f[k],f[i]);
                }
            }
            flag=check(k);
            for (int i=k+1;i<=n&&flag;i++) if (!pd(i)) flag=0;
        }
        if (flag==0) printf("N\n"); else printf("Y\n");
        for (int i=1;i<=n;i++) s[i].resize(0),f[i].resize(0);
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值