Censored! POJ - 1625 ac自动机+dp+高精度

2023-11-02 00:10

本文主要是介绍Censored! POJ - 1625 ac自动机+dp+高精度,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、内容

The alphabet of Freeland consists of exactly N letters. Each sentence of Freeland language (also known as Freish) consists of exactly M letters without word breaks. So, there exist exactly N^M different Freish sentences.But after recent election of Mr. Grass Jr. as Freeland president some words offending him were declared unprintable and all sentences containing at least one of them were forbidden. The sentence S contains a word W if W is a substring of S i.e. exists such k >= 1 that S[k] = W[1], S[k+1] = W[2], ...,S[k+len(W)-1] = W[len(W)], where k+len(W)-1 <= M and len(W) denotes length of W. Everyone who uses a forbidden sentence is to be put to jail for 10 years.Find out how many different sentences can be used now by freelanders without risk to be put to jail for using it.

Input

The first line of the input file contains three integer numbers: N -- the number of letters in Freish alphabet, M -- the length of all Freish sentences and P -- the number of forbidden words (1 <= N <= 50, 1 <= M <= 50, 0 <= P <= 10).The second line contains exactly N different characters -- the letters of the Freish alphabet (all with ASCII code greater than 32).The following P lines contain forbidden words, each not longer than min(M, 10) characters, all containing only letters of Freish alphabet.

Output

Output the only integer number -- the number of different sentences freelanders can safely use. 

Sample Input

2 3 1
ab
bb

Sample Output

5

二、思路

在这里插入图片描述

  • 由于方案数很多 故应该使用高精度。 还有注意输入的字符超出了char的范围会变成负数

三、代码

#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
#include <vector>
using namespace std;
const int N = 55, M = 110;
struct BigInteger{int A[25];enum{MOD = 10000};BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}void print(){printf("%d", A[A[0]]);for (int i=A[0]-1; i>0; i--){if (A[i]==0){printf("0000"); continue;}for (int k=10; k*A[i]<MOD; k*=10) printf("0");printf("%d", A[i]);}printf("\n");}int& operator [] (int p) {return A[p];}const int& operator [] (int p) const {return A[p];}BigInteger operator + (const BigInteger& B){BigInteger C;C[0]=max(A[0], B[0]);for (int i=1; i<=C[0]; i++)C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;if (C[C[0]+1] > 0) C[0]++;return C;}BigInteger operator * (const BigInteger& B){BigInteger C;C[0]=A[0]+B[0];for (int i=1; i<=A[0]; i++)for (int j=1; j<=B[0]; j++){C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;}if (C[C[0]] == 0) C[0]--;return C;}
};
int n, m, P, len, tr[M][N], ne[M], fail[M];
BigInteger dp[N][M];
char s[1000];
int mp[1000]; 
void add() {int p = 0;for (int i = 0; s[i]; i++) {int j = mp[(int)s[i] + 200];if (!tr[p][j]) tr[p][j] = ++len;p = tr[p][j];}fail[p] = 1;
}
void build() {queue<int> q;for (int j = 0; j < n; j++) {if (tr[0][j]) q.push(tr[0][j]);}while (!q.empty()) {int p = q.front(); q.pop();for (int j = 0; j < n; j++) {int c = tr[p][j];if (!c) tr[p][j] = tr[ne[p]][j];else {ne[c] = tr[ne[p]][j];fail[c] |= fail[ne[c]];q.push(c);}	}}
} int main() {scanf("%d%d%d", &n, &m, &P);scanf("%s", s);for (int i = 0; i < n; i++) {mp[(int)s[i] + 200] = i;}	for (int i = 1; i <= P; i++) {scanf("%s", s); add();}build();//进行dp求方案数 ]dp[0][0].set(1);for (int i = 1; i <= m; i++) {for (int j = 0; j <= len; j++) {for (int k = 0; k < n; k++) {int tj = tr[j][k]; //(i - 1, j)-->(i, tj)下一状态跳到哪儿 if (!fail[tj]) dp[i][tj] = dp[i][tj] + dp[i - 1][j];}} }BigInteger ans;for (int j = 0; j <= len; j++) ans = ans + dp[m][j];ans.print();return 0;
}

这篇关于Censored! POJ - 1625 ac自动机+dp+高精度的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/326750

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

poj 1511 Invitation Cards(spfa最短路)

题意是给你点与点之间的距离,求来回到点1的最短路中的边权和。 因为边很大,不能用原来的dijkstra什么的,所以用spfa来做。并且注意要用long long int 来存储。 稍微改了一下学长的模板。 stack stl 实现代码: #include<stdio.h>#include<stack>using namespace std;const int M

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];