[AC自动机] zoj Searching the String

题意:

给一个原串,再给n个串,每个串有属性,属性0代表可以重叠,1代表不可以重叠

问每个串出现了多少次

思路:

为了方便建立两个自动机(0的一个,1的一个)

然后可以重叠的很好做,以前都做过

不可重叠的话需要记录两个东西

len[i]代表每个串的长度,used[i]代表每个串在之前出现的位置,初始化-1

然后遍历到的时候对于当前位置 j, 必须j>=used[i]+len[i] 才能算出现,并且更新

需要注意的是:

会出现同样属性并且相同的串。我处理的方式就是排序,按id排序大的在前

然后算一遍大的,用大的赋值给id 小的且串相同的。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
char fuck[123456];
int ans[123456],used[123456],len[123456];
struct word
{
    int x,id;
    char y[7];
} dc[123456];
struct trie
{
    int mark;
    trie *next[27];
    trie *fail;
    trie()
    {
        mark=0;
        memset(next,0,sizeof(next));
        fail=NULL;
    }
};
trie *root0,*root1;
void init(int key,char *v,int id)
{
    trie *p;
    if(key) p=root1;
    else p=root0;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        if(p->next[tep]==NULL) p->next[tep]=new trie();
        p=p->next[tep];
    }
    p->mark=id;
}
void del(trie *p)
{
    for(int j=0; j<26; j++) if(p->next[j]!=NULL) del(p->next[j]);
    free(p);
}
void getac()
{
    queue<trie*>q;
    q.push(root0);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root0) p->next[i]->fail=root0;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root0;
                }
                q.push(p->next[i]);
            }
        }
    }
    q.push(root1);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root1) p->next[i]->fail=root1;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root1;
                }
                q.push(p->next[i]);
            }
        }
    }
}
void finde(char *v)
{
    trie *p0=root0,*p1=root1;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        while(p0->next[tep]==NULL && p0!=root0)
            p0=p0->fail;
        p0=p0->next[tep];
        if(p0==NULL) p0=root0;
        trie *q0=p0;
        while(q0!=root0)
        {
            if(q0->mark!=0) ans[q0->mark]++;
            q0=q0->fail;
        }
        while(p1->next[tep]==NULL && p1!=root1)
            p1=p1->fail;
        p1=p1->next[tep];
        if(p1==NULL) p1=root1;
        trie *q1=p1;
        while(q1!=root1)
        {
            if(q1->mark!=0)
            {
                if(i>=used[q1->mark]+len[q1->mark])  //不可重叠的判断
                {
                    ans[q1->mark]++;
                    used[q1->mark]=i;
                }
            }
            q1=q1->fail;
        }
    }
}
int cmp(word a,word b)  //排序的cmp
{
    if(a.x==b.x)
    {
        if(strcmp(a.y,b.y)==0)
        {
            if(a.id>b.id) return 1;
            else return 0;
        }
        else
        {
            if(strcmp(a.y,b.y)>0) return 1;
            else return 0;
        }
    }
    else
    {
        if(a.x>b.x) return 1;
        else return 0;
    }
}
int main()
{
    int cas=1;
    while(scanf("%s",fuck)!=-1)
    {
        int n;
        scanf("%d",&n);
        root0=new trie();
        root1=new trie();
        for(int i=1; i<=n; i++)
        {
            int x;
            char y[12];
            scanf("%d%s",&x,y);
            len[i]=strlen(y);
            init(x,y,i);
            dc[i].x=x;
            strcpy(dc[i].y,y);
            dc[i].id=i;
        }
        memset(ans,0,sizeof(ans));
        memset(used,-1,sizeof(used));
        getac();
        finde(fuck);
        sort(dc+1,dc+1+n,cmp);
        int i;
        for(i=1; dc[i+1].x==1; i++)  //赋值给那些重复的
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        for(i=i+1; i<n; i++)
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        printf("Case %d\n",cas++);
        for(int i=1; i<=n; i++) printf("%d\n",ans[i]);
        del(root0);
        del(root1);
        puts("");
    }
    return 0;
}


深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值