HihoCoder - 1877 2018北京H AC自动机dp

https://hihocoder.com/login

模拟赛的时候强行迭代dp做的题,事实上是AC自动机的套路题,虽说迭代不用算法比较亲民,但是确实抠细节不太好写,当时也写了有一个小时,如果知道这是一道AC自动机的套路题的话,就好做多了

将N + 1个模式串插入AC自动机之后,如果进入到末尾结点就在贡献处加上(1LL << M - i + 1) * 方案数的贡献,表示当前长度有多少种可能到达这个节点,同时到达了之后后面的所有节点都可以任选。

 

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 2010;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
char str[maxn];
int nxt[maxn][26],tot,fail[maxn],ed[maxn],root;
int newnode(){
    for(int i = 0 ; i < 2; i ++) nxt[tot][i] = -1;
    ed[tot++] = 0;
    return tot - 1;
}
void init(){
    tot = 0;
    root = newnode();
}
void insert(char *str){
    int p = root;
    for(int i = 0; str[i]; i ++){
        int id = str[i] - '0';
        if(nxt[p][id] == -1) nxt[p][id] = newnode();
        p = nxt[p][id];
    }
    ed[p] = 1;
}
void Build(){
    queue<int>Q;
    fail[root] = root;
    for(int i = 0;i < 2; i ++){
        if(~nxt[root][i]){
            fail[nxt[root][i]] = root;
            Q.push(nxt[root][i]);
        }else{
            nxt[root][i] = root;
        }
    }
    while(!Q.empty()){
        int u = Q.front(); Q.pop();
        for(int i = 0 ; i < 2; i ++){
            if(~nxt[u][i]){
                fail[nxt[u][i]] = nxt[fail[u]][i];
                ed[nxt[u][i]] |= ed[nxt[fail[u]][i]];
                Q.push(nxt[u][i]);
            }else{
                nxt[u][i] = nxt[fail[u]][i];
            }
        }
    }
}
LL dp[2][maxn];
int main(){
    int T = read();
    while(T--){
        Sca2(N,M); init(); 
        scanf("%s",str); insert(str);
        for(int i = 0 ; i < N ; i ++){
            if(str[i] == '1') str[i] = '0';
            else str[i] = '1';
            insert(str);
            if(str[i] == '1') str[i] = '0';
            else str[i] = '1';
        }
        Build();
        LL ans = 0;
        dp[0][0] = 1;
        for(int i = 1 ; i <= M ; i ++){
            for(int j = 0 ; j < tot; j ++) dp[i & 1][j] = 0;
            for(int j = 0 ; j < tot; j ++){
                if(ed[j]) continue;
                for(int k = 0 ; k < 2; k ++){
                    if(ed[nxt[j][k]]){
                        ans += dp[i + 1 & 1][j] * (1LL << (M - i));
                    }else{
                        dp[i & 1][nxt[j][k]] += dp[i + 1 & 1][j];
                    }
                }
            }
        }
        Prl(ans);
        for(int j = 0 ; j < tot; j ++) dp[0][j] = dp[1][j] = 0;
    }
    return 0; 
}

 

posted @ 2019-09-05 21:11  Hugh_Locke  阅读(378)  评论(0编辑  收藏  举报