题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种?

分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中的步骤是一样的,只不过最后的DP状态转移方式 2778 是利用了矩阵进行转移的,那是因为需要构造的串的长度非常长!只能利用矩阵转移。但是这道题需要构造的串的长度最多也就只有 50 ,可以利用普通的DP方法进行转移。我们定义 DP[i][j] 为以长度为 i 以字符 j 为结尾的串的种类数是多少,那么状态转移方程很显然就是 DP[i+1][k] += DP[i][j] * G[j][k] 这个方程表示现在 k 到 j 有一条边并且从k 走一步可以到 j 的方案数是 G[j][k] ( Trie 图构建出来的 ),那么现在 DP[i+1][k] 就很明显可以从 DP[i][j] 转移而来,DP的初始状态为 DP[0][0] = 0 && DP[0][i] = 0。

注意 :

① 因为没有要求对答案进行求模运算,答案可能很大,因为如果 p = 0,而n 和 m 都达到最大的50,那么答案就是 50^50,所以需要用到高精度。

② 字符可能有超过 128 的,也就是有负数情况,用map转化

#include<string.h>
#include<stdio.h>
#include<iostream>
#include<queue>
#include<map>
using namespace std;
const int Max_Tot = ;
const int Letter = ;
int G[][], n;
map<int, int> mp;
struct bign{
#define MAX_B (100)
#define MOD (10000)
int a[MAX_B], n;
bign() { a[] = , n = ; }
bign(int num)
{
n = ;
do {
a[n++] = num % MOD;
num /= MOD;
} while(num);
}
bign& operator= (int num)
{ return *this = bign(num); }
bign operator+ (const bign& b) const
{
bign c = bign();
int cn = max(n, b.n), d = ;
for(int i = , x, y; i < cn; i++)
{
x = (n > i) ? a[i] : ;
y = (b.n > i) ? b.a[i] : ;
c.a[i] = (x + y + d) % MOD;
d = (x + y + d) / MOD;
}
if(d) c.a[cn++] = d;
c.n = cn;
return c;
}
bign& operator+= (const bign& b)
{
*this = *this + b;
return *this;
}
bign operator* (const bign& b) const
{
bign c = bign();
int cn = n + b.n, d = ;
for(int i = ; i <= cn; i++)
c.a[i] = ;
for(int i = ; i < n; i++)
for(int j = ; j < b.n; j++)
{
c.a[i + j] += a[i] * b.a[j];
c.a[i + j + ] += c.a[i + j] / MOD;
c.a[i + j] %= MOD;
}
while(cn > && !c.a[cn-]) cn--;
if(!cn) cn++;
c.n = cn;
return c;
}
friend ostream& operator<< (ostream& _cout, const bign& num)
{
printf("%d", num.a[num.n - ]);
for(int i = num.n - ; i >= ; i--)
printf("%04d", num.a[i]);
return _cout;
}
};
struct Aho{
struct StateTable{
int Next[Letter];
int fail, flag;
}Node[Max_Tot];
int Size;
queue<int> que; inline void init(){
while(!que.empty()) que.pop();
memset(Node[].Next, , sizeof(Node[].Next));
Node[].fail = Node[].flag = ;
Size = ;
} inline void insert(char *s){
int now = ;
for(int i=; s[i]; i++){
int idx = mp[s[i]];
if(!Node[now].Next[idx]){
memset(Node[Size].Next, , sizeof(Node[Size].Next));
Node[Size].fail = Node[Size].flag = ;
Node[now].Next[idx] = Size++;
}
now = Node[now].Next[idx];
}
Node[now].flag = ;
} inline void BuildFail(){
Node[].fail = ;
for(int i=; i<n; i++){
if(Node[].Next[i]){
Node[Node[].Next[i]].fail = ;
que.push(Node[].Next[i]);
}else Node[].Next[i] = ;///必定指向根节点
}
while(!que.empty()){
int top = que.front(); que.pop();
if(Node[Node[top].fail].flag) Node[top].flag = ;
for(int i=; i<n; i++){
int &v = Node[top].Next[i];
if(v){
que.push(v);
Node[v].fail = Node[Node[top].fail].Next[i];
}else v = Node[Node[top].fail].Next[i];
}
}
} inline void BuildMap(){
for(int i=; i<Size; i++)
for(int j=; j<Size; j++)
G[i][j] = ; for(int i=; i<Size; i++){
for(int j=; j<n; j++){
if(!Node[ Node[i].Next[j] ].flag)
G[i][Node[i].Next[j]]++;
}
}
}
}ac; #define MAX_M (55)
bign dp[MAX_M][Max_Tot]; char s[];
int main(void)
{
int m, p;
while(~scanf("%d %d %d\n", &n, &m, &p)){
mp.clear();
gets(s);
int len = strlen(s);
for(int i=; i<len; i++)
mp[s[i]] = i; ac.init();
for(int i=; i<p; i++){
gets(s);
ac.insert(s);
}
ac.BuildFail();
ac.BuildMap(); for(int i=; i<=m; i++)
for(int j=; j<ac.Size; j++)
dp[i][j] = bign(); dp[][] = ;
for(int i=; i<m; i++)
for(int j=; j<ac.Size; j++){
for(int k=; k<ac.Size; k++){
dp[i+][k] += dp[i][j] * G[j][k];
}
} bign ans = bign(); for(int i=; i<ac.Size; i++)
ans += dp[m][i]; cout<<ans<<endl;
}
return ;
}

POJ 1625 Censored ( Trie图 && DP && 高精度 )的更多相关文章

  1. POJ 1625 Censored!(AC自动机+DP+高精度)

    Censored! Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 6956   Accepted: 1887 Descrip ...

  2. POJ 1625 Censored!(AC自动机+高精度+dp)

    http://poj.org/problem?id=1625 题意: 给出一些单词,求长度为m的串不包含这些单词的个数. 思路: 这道题和HDU 2243和POJ 2778是一样的,不同的是这道题不取 ...

  3. Censored! - POJ 1625(ac自动机+简单dp+高精度运算)

    题目大意:首先给一个字符集合,这个集合有N个字符,然后需要一个长度为M的句子,但是据子里面不能包含的串有P个,每个串里面的字符都是有字符集和里面的字符构成的,现在想知道最多能构造多少个不重复的句子. ...

  4. 【Trie图+DP】BZOJ1030[JSOI2007]-文本生成器

    [题目大意] 给出单词总数和固定的文章长度M,求出至少包含其中一个单词的可能文章数量. [思路] 对于至少包含一个的类型,我们可以考虑补集.也就是等于[总的文章可能性总数-不包含任意一个单词的文章总数 ...

  5. POJ 3691 DNA repair ( Trie图 && DP )

    题意 : 给出 n 个病毒串,最后再给出一个主串,问你最少改变主串中的多少个单词才能使得主串中不包含任何一个病毒串 分析 : 做多了AC自动机的题,就会发现这些题有些都是很套路的题目.在构建 Trie ...

  6. POJ 1625 Censored!(大数+DP)

    题目链接 这题,真心木啥意思,就是数据里貌似字符有负数,注意gets读入.. #include <iostream> #include <cstring> #include & ...

  7. HDU 2296 Ring ( Trie图 && DP && DP状态记录)

    题意 : 给出 m 个单词,每一个单词有一个权重,如果一个字符串包含了这些单词,那么意味着这个字符串拥有了其权重,问你构成长度为 n 且权重最大的字符串是什么 ( 若有权重相同的,则输出最短且字典序最 ...

  8. hdu2457 Trie图+dp

    hdu2457 给定n个模式串, 和一个文本串 问如果修改最少的字符串使得文本串不包含模式串, 输出最少的次数,如果不能修改成功,则输出-1 dp[i][j] 表示长度为i的字符串, 到达状态j(Tr ...

  9. BZOJ1212: [HNOI2004]L语言(Trie图+DP)

    Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D ...

随机推荐

  1. python计算1~100的和,1~100奇数的和,1~100偶数的和,一条代码求1~100的和

    1.计算1~100的数之和----for循环实现1~100的和 sum1 = ,): sum1 = sum1 + i i += print(f"1-100之间的和是:{sum1}" ...

  2. TCP和UDP头部格式的了解?

    tcp头部格式如下图所示: 1.源端口号,16位,发送方的端口号. 2.目标端口号,16位,发送方的目标端口号. 3.  32为序列号,sequence number,保证网络传输数据的顺序性. 4. ...

  3. Longest Subsequence CodeForces - 632D (lcm)

    大意: 给定序列$a$, 求选出最长的一个子序列, 使得lcm不超过m. 刚开始想复杂了, 想着枚举gcd然后背包, 这样复杂度就是$O(\sum\limits_{i=1}^m \frac{m\sig ...

  4. Elasticsearch入门教程(二):Elasticsearch核心概念

    原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:ht ...

  5. 一分钟理解sku和spu

    SPU SPU = Standard Product Unit (标准化产品单位) SPU是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该集合描述了一个产品的特性.通俗点讲,属性值 ...

  6. CF1090H Linearization

    传送门 先考虑什么样的串才符合条件.\(s_i=P(x\&i)\oplus b\),其实这里的\(b\)只能使得整体是否取反,所以可以先不管.然后考虑\(x\)的每个二进制位的对\(s_0\) ...

  7. 解决 "Could not autowire. No beans of 'SationMapper' type found" 的问题

    网上查找的方法,附上原文链接:https://blog.csdn.net/Coder_Knight/article/details/83999139 方法1:在mapper文件上加@Repositor ...

  8. redis之使用场景

    随着数据量的增长,MySQL 已经满足不了大型互联网类应用的需求.因此,Redis 基于内存存储数据,可以极大的提高查询性能,对产品在架构上很好的补充.在某些场景下,可以充分的利用 Redis 的特性 ...

  9. jfinal layui easyexcel 实现文件的上传下载

    jfinal  layui easyexcel  这三样开源技术这里就不多介绍了,自行百度了解吧,他们的组合算是一个很高效又不失美观的操作体验. 操作主要分以下几步: 1.建立jfinal的操作环境, ...

  10. 安装Python包报错——ReadTimeoutError

    一.问题:安装python包的时候报错ReadTimeoutError——Read time out. 二.解决办法三种方法,一是切换下载源:二是下载相应平台的安装包后安装:三是下载源码编译安装:  ...