• 2018北京区域赛 Approximate Matching (AC自动机+dp)


    这道题我们首先发现因为最多就一个地方不一样,因此其实最终的答案就是n+1个字符串所产生的,也就是对于给定串,只改一位以及原串加入字典树

    之后的做法和一道经典例题(文本打印机)一毛一样,就是枚举在哪个节点跑ac自动机+dp

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    const int mod=1e9+7;
    string s;
    struct node{
        int cnt;
        node *nxt[2];
        node *fail;
    }*rt;
    int num,idx;
    node pool[666][6100];
    int val[N];
    ll f[105][6100][2];
    int n,m;
    int sum;
    void insert(string s,int x){
        node *p=rt;
        int i;
        for(i=0;i<s.size();i++){
            int sign=s[i]-'0';
            if(p->nxt[sign]==NULL){
                p->nxt[sign]=pool[sum]+(++idx);
                p->nxt[sign]->cnt=++num;
            }
            p=p->nxt[sign];
            if(i==(int)s.size()-1){
                val[p->cnt]=x;
            }
        }
    }
    void build(){
        int i;
        queue<node *> q;
        rt->fail=rt;
        for(i=0;i<2;i++){
            if(rt->nxt[i]){
                rt->nxt[i]->fail=rt;
                q.push(rt->nxt[i]);
            }
            else{
                rt->nxt[i]=rt;
                rt->nxt[i]->fail=rt;
            }
        }
        while(q.size()){
            auto t=q.front();
            q.pop();
            for(i=0;i<2;i++){
                if(t->nxt[i]){
                    t->nxt[i]->fail=t->fail->nxt[i];
                    q.push(t->nxt[i]);
                }
                else{
                    t->nxt[i]=t->fail->nxt[i];
                }
            }
            val[t->cnt]|=val[t->fail->cnt];
        }
    }
    void init(){
        memset(f,0,sizeof f);
        int i;
        for(i=0;i<=num;i++)
            val[i]=0;
    }
    int main(){
        ios::sync_with_stdio(false);
        int t;
        cin>>t;
        int i,j,k;
        while(t--){
            init();
            rt=pool[sum];
            rt->cnt=0;
            idx=0,num=0;
            cin>>n>>m;
            cin>>s;
            insert(s,1);
            for(i=0;i<(int)s.size();i++){
                if(s[i]=='1')
                    s[i]='0';
                else
                    s[i]='1';
                insert(s,1);
                if(s[i]=='1')
                    s[i]='0';
                else
                    s[i]='1';
            }
    
            build();
            f[0][0][0]=1;
            for(i=1;i<=m;i++){
                for(j=0;j<=num;j++){
                    for(k=0;k<=1;k++){
                        int id=(pool[sum]+j)->nxt[k]->cnt;
                        if(val[id]){
                            f[i][id][1]+=f[i-1][j][1]+f[i-1][j][0];
                        }
                        else{
                            f[i][id][1]+=f[i-1][j][1];
                            f[i][id][0]+=f[i-1][j][0];
                        }
                    }
                }
            }
            ll ans=0;
            for(i=0;i<=num;i++)
                ans+=f[m][i][1];
            cout<<ans<<endl;
            sum++;
        }
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    【Python3爬虫】一次应对JS反调试的记录
    【Python3爬虫】突破反爬之应对前端反调试手段
    学习CSS之如何改变CSS伪元素的样式
    学习CSS之用CSS实现时钟效果
    学习CSS之用CSS绘制一些基本图形
    【Python3爬虫】一次破解JS加密数据的记录
    Linux安装部署Redis(超级详细)
    Linux部署MongoDB
    使用Nginx对.NetCore站点进行反向代理
    Linux部署.NetCore站点 使用Supervisor进行托管部署
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13537781.html
Copyright © 2020-2023  润新知