POJ 1625 Censored ( Trie图 && DP && 高精度 )
题意 : 给出 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 && 高精度 )的更多相关文章
- POJ 1625 Censored!(AC自动机+DP+高精度)
Censored! Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 6956 Accepted: 1887 Descrip ...
- POJ 1625 Censored!(AC自动机+高精度+dp)
http://poj.org/problem?id=1625 题意: 给出一些单词,求长度为m的串不包含这些单词的个数. 思路: 这道题和HDU 2243和POJ 2778是一样的,不同的是这道题不取 ...
- Censored! - POJ 1625(ac自动机+简单dp+高精度运算)
题目大意:首先给一个字符集合,这个集合有N个字符,然后需要一个长度为M的句子,但是据子里面不能包含的串有P个,每个串里面的字符都是有字符集和里面的字符构成的,现在想知道最多能构造多少个不重复的句子. ...
- 【Trie图+DP】BZOJ1030[JSOI2007]-文本生成器
[题目大意] 给出单词总数和固定的文章长度M,求出至少包含其中一个单词的可能文章数量. [思路] 对于至少包含一个的类型,我们可以考虑补集.也就是等于[总的文章可能性总数-不包含任意一个单词的文章总数 ...
- POJ 3691 DNA repair ( Trie图 && DP )
题意 : 给出 n 个病毒串,最后再给出一个主串,问你最少改变主串中的多少个单词才能使得主串中不包含任何一个病毒串 分析 : 做多了AC自动机的题,就会发现这些题有些都是很套路的题目.在构建 Trie ...
- POJ 1625 Censored!(大数+DP)
题目链接 这题,真心木啥意思,就是数据里貌似字符有负数,注意gets读入.. #include <iostream> #include <cstring> #include & ...
- HDU 2296 Ring ( Trie图 && DP && DP状态记录)
题意 : 给出 m 个单词,每一个单词有一个权重,如果一个字符串包含了这些单词,那么意味着这个字符串拥有了其权重,问你构成长度为 n 且权重最大的字符串是什么 ( 若有权重相同的,则输出最短且字典序最 ...
- hdu2457 Trie图+dp
hdu2457 给定n个模式串, 和一个文本串 问如果修改最少的字符串使得文本串不包含模式串, 输出最少的次数,如果不能修改成功,则输出-1 dp[i][j] 表示长度为i的字符串, 到达状态j(Tr ...
- BZOJ1212: [HNOI2004]L语言(Trie图+DP)
Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D ...
随机推荐
- 使用Koa.js离不开这十个中间件
随着ES6的普及,async/await的语法受到更多JS开发者的青睐,Koa.js作为比较早支持使用该语法的Node框架越来越受到大家的喜爱,虽然Koa.js本身支持的功能很有限,但官方和社区提供了 ...
- Linux的环境变量.bash_profile .bashrc profile文件
Shell变量有局部变量.环境变量之分.局部变量就是指在某个Shell中生效的变量,只在此次登录中有效.环境变量通常又称“全局变量”,虽然在Shell中变量默认就是全局的,但是为了让子Shall继承当 ...
- [Vue] vue-router-interview
1.vue-router 怎么重定向页面? 路由中配置 redirect 属性 使用路由的别名来完成重定向 2.vue-router 怎么配置 404 页面? path: '*',放在最后一个 3.切 ...
- css 空心圆
用css实现一个空心圆,并始终放置在浏览器窗口左下角 div{ position:fixed; bottom:0; ...
- vue报错 Missing required prop: "value"-----(v-model 与 :model的区别)
找不到value值 原因:这个错是因为自己绑定值得问题,将v-model 写成了:model . v-model: 是vue内置的双向数据绑定,父子组件的双向绑定,通常用于input数据的双向绑定,用 ...
- 推荐JavaScript动态效果库
翻译:疯狂的技术宅,原文:https://blog.bitsrc.io/11-javascript-animation-libraries-for-2018-9d7ac93a2c59 当我想要在网上找 ...
- vnd.ms-excel.numberformat 导出Ecxel 格式
<td style="vnd.ms-excel.numberformat:@;"><s:property value="accountCode" ...
- centos7 mysql 各种报错
1.重置root密码 vi /etc/my.cnf 添加skip-grant-tables service mysqld restart 2.mysql 登录 报错1 Unknown system v ...
- hdu 6205 card card card 最大子段和
#include<iostream> #include<deque> #include<memory.h> #include<stdio.h> #inc ...
- 认识JWT(转)
1. JSON Web Token是什么 JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的.自包含的方式,用于作为JSON对象在各方之间安全地传输信息.该 ...