zoukankan      html  css  js  c++  java
  • Foj 2299 Prefix(AC自动机、DP)

    Foj 2299 Prefix

    题意

    给定串s、正整数n,问有多少长度为n的字符串t满足:s[0...i]是t的子串,s[0...i+1]不是。

    题解

    求有多少长度为n的字符串t满足:s[0...i]是t的子串
    这样求出来的数列就是答案的一个前缀和。

    具体求法可以对于s[0...i]建一个AC自动机,列出dp式子,状态转移矩阵就很好构造了。
    现场主要是没想到每个前缀的方案数要分开求。

    代码

    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<iostream>
    using namespace std;
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define rep(i, a, b) for(int i=(a); i<(b); i++)
    #define sz(a) (int)a.size()
    #define de(a) cout << #a << " = " << a << endl
    #define dd(a) cout << #a << " = " << a << " "
    #define all(a) a.begin(), a.end()
    #define endl "
    "
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef vector<int> vi;
    
    const int N = 22, P = 1e9+7;
    
    int n, m;
    int f[N];
    string s;
    
    int kpow(int a, int b) {
    	int res = 1;
    	while(b) {
    		if(b&1) res = 1ll*res*a%P;
    		a = 1ll*a*a%P;
    		b >>= 1;
    	}
    	return res;
    }
    
    inline int add(int a, int b) {
    	a+=b;
    	if(a>=P) a-=P;
    	return a;
    }
    inline int sub(int a, int b) {
    	a-=b;
    	if(a<0) a+=P;
    	return a;
    }
    inline int mul(int a, int b) {
    	return 1ll*a*b%P;
    }
    
    struct Mat {
    	static const int N = ::N;
    	int a[N][N], n;
    	Mat(){} Mat(int _n, int v) { n = _n; rep(i, 0, n) rep(j, 0, n) a[i][j] = i==j ? v : 0; }
    	Mat operator * (const Mat &c) const {
    		Mat res(n, 0);
    		rep(i, 0, n) rep(j, 0, n) rep(k, 0, n) res.a[i][j] = add(res.a[i][j], mul(a[i][k], c.a[k][j]));
    		return res;
    	}
    	Mat operator ^ (int b) const {
    		Mat res(n, 1), a = *this;
    		while(b) {
    			if(b&1) res = res*a;
    			a = a*a;
    			b>>=1;
    		}
    		return res;
    	}
    };
    struct Trie {
    	static const int N = ::N, M = 26;
    	int ne[N][M], fail[N], fa[N], rt, L, ed[N];
    	void init() {
    		fill_n(ne[fail[0] = N-1], M, 0);
    		fill_n(ed, L, 0);
    		L = 0;
    		rt = newnode();
    	}
    	int newnode() {
    		fill_n(ne[L], M, 0);
    		return L++;
    	}
    	void add(string s) {
    		int p = rt;
    		rep(i, 0, sz(s)) {
    			int c = s[i] - 'A';
    			if(!ne[p][c]) ne[p][c] = newnode(), fa[L-1] = p;
    			p = ne[p][c];
    		}
    		ed[p] = 1;
    	}
    	void build() {
    		vi v;v.pb(rt);
    		rep(i, 0, sz(v)) {
    			int c = v[i];
    			rep(i, 0, M) ne[c][i] ? 
    				v.pb(ne[c][i]), fail[ne[c][i]] = ne[fail[c]][i] :
    				ne[c][i] = ne[fail[c]][i];
    		}
    	}
    	Mat getMat() {
    		Mat mat(L, 0);
    		rep(i, 0, L) rep(j, 0, M) {
    			int nex = ed[i] ? i : ne[i][j];
    			++mat.a[i][nex];
    		}
    		return mat;
    	}
    }ac;
    
    int main() {
    	std::ios::sync_with_stdio(false);
    	std::cin.tie(0);
    	int T;
    	cin >> T;
    	while(T--) {
    		cin >> n >> m >> s;
    		f[0] = kpow(26, n);
    		rep(i, 1, m+1) {
    			ac.init();
    			ac.add(s.substr(0, i));
    			ac.build();
    			Mat res = ac.getMat() ^ n;
    			f[i] = res.a[0][i];
    		}
    		rep(i, 0, m) f[i] = sub(f[i], f[i+1]);
    		rep(i, 0, m+1) cout << f[i] << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    如何以nobody用户执行命令?
    记一次全站代理切换----血的教训
    tomcat十大安全优化措施
    paramiko模块使用
    日志分析 第七章 安装grafana
    日志分析 第六章 安装elasticsearch
    日志分析 第五章 安装logstash
    日志分析 第四章 安装filebeat
    IO多路复用及ThreadingTCPServer源码阅读
    socket编程--socket模块介绍
  • 原文地址:https://www.cnblogs.com/wuyuanyuan/p/9220141.html
Copyright © 2011-2022 走看看