zoukankan      html  css  js  c++  java
  • [洛谷P4052][JSOI2007]文本生成器

    题目大意:有$n$个字符串$s_i$,问有多少个长度为$m$的字符串至少包含$n$个字符串中的一个,字符集 A-Z 。$s_i,mleqslant100,nleqslant60$

    题解:$AC$自动机上$DP$,转换问题为求有多少个长度为$m$的字符串不包含$n$个字符串中的任意一个。定义$f[i][j]$表示现在字符串长度为$i$,匹配到了$AC$自动机上的点$j$且没有出现$n$个字符串中的任意一个的方案数,发现$f[i][j]$可转移到$f[i+1][nxt[j][k]]$。注意,要求$nxt[j][k]$不能是一个串的结尾。可以发现若$nxt[j][k]$的$fail$中没有串的结尾就是合法的,这一个可以在求$fail$时顺带求出

    卡点:

    C++ Code:

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <queue>
    const int maxn = 110 * 60, mod = 10007;
    inline void reduce(int &x) { x += x >> 31 & mod; }
    
    int n, m, ans = 1;
    
    namespace AC {
    	int nxt[maxn][26], fail[maxn], idx = 1;
    	bool End[maxn];
    	void insert(std::string s) {
    		int p = 1;
    		for (char ch : s) {
    			if (nxt[p][ch - 'A']) p = nxt[p][ch - 'A'];
    			else p = nxt[p][ch - 'A'] = ++idx;
    		}
    		End[p] = true;
    	}
    	void build() {
    		static std::queue<int> q;
    		for (int i = 0; i < 26; ++i)
    			if (nxt[1][i]) fail[nxt[1][i]] = 1, q.push(nxt[1][i]);
    			else nxt[1][i] = 1;
    		while (!q.empty()) {
    			int u = q.front(); q.pop();
    			for (int i = 0; i < 26; ++i)
    				if (nxt[u][i]) {
    					fail[nxt[u][i]] = nxt[fail[u]][i];
    					End[nxt[u][i]] |= End[fail[nxt[u][i]]];
    					q.push(nxt[u][i]);
    				} else nxt[u][i] = nxt[fail[u]][i];
    		}
    	}
    
    	void solve() {
    		static std::queue<int> q[2];
    		int f[111][maxn], tg[maxn];
    		int now = 1, pst = 0, u;
    		q[now].push(1);
    		f[0][1] = 1;
    		for (int i = 0; i < m; ++i) {
    			std::swap(now, pst);
    			while (!q[pst].empty()) {
    				u = q[pst].front(), q[pst].pop();
    				for (int j = 0; j < 26; ++j)
    					if (!End[nxt[u][j]]) {
    						reduce(f[i + 1][nxt[u][j]] += f[i][u] - mod);
    						if (tg[nxt[u][j]] != i + 1) q[now].push(nxt[u][j]);
    						tg[nxt[u][j]] = i + 1;
    					}
    			}
    		}
    		for (; !q[now].empty(); q[now].pop())
    			reduce(ans -= f[m][q[now].front()]);
    	}
    }
    
    int main() {
    	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
    	std::cin >> n >> m;
    	for (int i = 1; i <= m; ++i) ans = ans * 26 % mod;
    	for (int i = 0; i < n; ++i) {
    		static std::string s;
    		std::cin >> s;
    		AC::insert(s);
    	}
    	AC::build(), AC::solve();
    	std::cout << ans << '
    ';
    	return 0;
    }
    

      

  • 相关阅读:
    关闭ThinkPHP Runtime Log
    Robots协议的写法
    Getif工具获取 交换机的OID/Zabbix设置
    命令方式启动 vmware 虚拟机
    wireshark 抓包使用教程
    Sniffer 交换机端口抓包
    H3C 开启ssh/snmp
    Apache Superset BI
    洛谷5588 小猪佩奇爬树
    luogu5536 核心城市
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/11305126.html
Copyright © 2011-2022 走看看