1. 程式人生 > 實用技巧 >2018北京區域賽 Approximate Matching (AC自動機+dp)

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