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 ...
随机推荐
- Python 入门之 软件开发规范
Python 入门之 软件开发规范 1.软件开发规范 -- 分文件 (1)为什么使用软件开发规范: 当几百行--大几万行代码存在于一个py文件中时存在的问题: 不便于管理 修改 可读性差 加载速度慢 ...
- 数据库中的round()
Round函数返回一个数值,该数值是按照指定的小数位数进行四舍五入运算的结果.可是当保留位跟着的即使是5,有可能进位,也有可能舍去,机会各50%.这样就会造成在应用程序中计算有误. 参数规范 语法 r ...
- php开发环境推荐使用
万丈高楼平地起,好用得环境才能建立宏伟大厦,php开发环境推荐使用 1,自己安装 lamp 环境 linux+apache+mysql+php 2,自己安装 lnmp 环境 linux+nginx+m ...
- 32、出任爬虫公司CEO(爬取职友网招聘信息)
职友集,搜索到全国上百家招聘网站的最新职位. https://www.jobui.com/rank/company/ 打开网址后,你会发现:这是职友集网站的地区企业排行榜,里面含有 本 ...
- 利用bing图片搜索接口开发图片搜索应用程序
概述:通过bing的图片搜索引擎,开发自己的图片搜索应用程序.bing的图片搜索接口是收费的,但是初次注册使用,key可以免费试用30天 程序运行效果如下 一,代码如下 static SearchRe ...
- redis远程连接配置
解决redis远程连接不上的问题 redis现在的版本开启redis-server后,redis-cli只能访问到127.0.0.1,因为在配置文件中固定了ip,因此需要修改redis.conf(有的 ...
- 纯CSS绘制3D立方体
本篇记录的是使用CSS3绘制3D立方体,并旋转起来. 我的思路: 1️⃣ 首先,用div元素画6个正方形摞在一起放在画布中间.为了区分,分别给每个div选择了不同的颜色,并且设置为半透明方便透视. 2 ...
- GDAL支持中文路径和Shp文件中文属性写入
在使用GDAL的过程中,为了支持中文,比需手动进行中文路径的设置,同时特别是在对Shp的属性进行中文输入的时候,都必须进行必要的设定. 为了支持中文路径,在注册了驱动之后,加上第三句就可以了.必须设置 ...
- nodejs fs copy本地文件src dst
1. // fs.writeFileSync(pathNewFile, fs.readFileSync(fileName)); 2. fs.createReadStream(fileName).p ...
- Python3使运行暂停的方法
在Python3中已经有很大一部分语句与Python2不互通了,运行暂停的方法也有所不同. 1.input(); 这种方法不用包含模块,因此这也是最常用的一种暂停手段. Python2中的raw_in ...