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
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13537781.html