bzoj4502 串
题意:给你n(n<=10000)个字符串,每个字符串的长度不超过30,可以选择两个非空前缀把它们拼起来得到一个字符串(这两个前缀可以来自同一个字符串,也可以是同一个字符串的同一个非空前缀),问得到的所有字符串中有多少个本质不同的字符串.
首先看到一堆字符串的前缀我们就可以想AC自动机,这个题意看上去只要在AC自动机上DP一下就好了,然后我看了眼题解发现确实是AC自动机上DP,然后就开始想怎么DP,想了2h才搞出来...交一发T了,减少无用状态的转移A了,15s,榜上倒数第二...(后来把指针+动态内存改为指针+静态内存,18s了...目测是大数组申请和构造函数的锅?)
其实我虽然搞出来了但是并不能讲明白
那么怎么DP呢?首先我们需要把一个可行的字符串对应为AC自动机上从根节点出发的一条路径,然后有两种情况,一种是这条路径没有沿着fail指针往回走过,那么这条路径本身也对应着某个串的一个前缀,我们在AC自动机上遍历一遍(实现时可以在求fail指针时顺便做)就可以统计所有的这种路径,判断这条路径能否拆分成两个前缀就只需看路径的终点的fail指针是否指向根节点即可(如果不指向根节点,那么fail指针指向的那个节点对应了拆分方案中后面的那个前缀,而去掉后面那个前缀之后,这条路径前面的部分必然还是一个前缀).
第二种情况就是这条路径沿着fail指针往回走过. 这种情况比上一种情况复杂.如何判断一条路径是否合法?我们可以在这条路径的开头找出一个尽量长的前缀,然后在这条路径的结尾找出一个尽量长的前缀,判断这样的两个前缀能否组成整条路径.那么开头位置的尽量长的前缀对应着从AC自动机的根节点走到这条路径第一次跳fail指针的位置.假如在第一次跳fail指针后走了x步到达了终点,那么终点的深度对应着这条路径结尾位置的最长前缀.只要终点的深度大于等于x,我们就能找到合法的拆分方案把这条路径拆成两个前缀.
那么定义状态时首先可以想到f[i][j][k]表示从第i个节点第一次跳fail指针,走了j步到达一个深度为k的节点的方案有多少,这样好像会MLE+TLE.注意到从哪个位置开始第一次跳fail指针并没有什么用,我们关注的是终点的深度,那么定义f[i][j]表示第一次跳fail指针之后走了j步到达节点i的方案有多少,我写的复杂度是O(节点总数*最大深度*字符集大小),也就是300000×30×26....减少一些无用状态的转移之后能15s跑过去也是感人....榜上大神们都跑得好快呀不知道是有复杂度更好的方法还是我的常数太丑了?不过加了滚动数组之后10s了233333
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=;
struct node{
node* ch[],*fail;
int num,depth;
node(){}
node(int x,int d){depth=d;memset(ch,,sizeof(ch));fail=;num=x;}
}*root;int tot=;
char str[];
node* pos[maxn];
void Add(char *c){
node* p=root;
while(*c){
int t=*c-'a';
if(p->ch[t]==NULL){p->ch[t]=new node(++tot,p->depth+);pos[tot]=p->ch[t];}
p=p->ch[t];++c;
}
}
long long f[][maxn];
long long ans=;
void getfail(){
queue<node*> q;q.push(root);
while(!q.empty()){
node* x=q.front();q.pop();
if(x!=root&&x->fail!=root)ans++;
for(int i=;i<;++i){
if(x->ch[i]){
if(x==root)x->ch[i]->fail=root;
else x->ch[i]->fail=x->fail->ch[i];
q.push(x->ch[i]);
}else{
if(x==root)x->ch[i]=root;
else x->ch[i]=x->fail->ch[i];
f[][x->ch[i]->num]++;
}
}
}
}
int main(){
int n;scanf("%d",&n);int maxlen=;
root=new node(,);pos[]=root;
for(int i=;i<=n;++i){
scanf("%s",str);int len=strlen(str);if(len>maxlen)maxlen=len;
Add(str);
}
getfail();
int flag=;
for(int k=;k<=maxlen;++k){
for(int i=;i<=tot;++i)f[flag^][i]=;
for(int i=;i<=tot;++i){
if(f[flag][i]==||pos[i]->depth<k)continue;
for(int j=;j<;++j){
f[flag^][pos[i]->ch[j]->num]+=f[flag][i];
}
if(k<=pos[i]->depth)ans+=f[flag][i];
//printf("f[%d][%d]==%lld\n",i,k,f[i][k]);
}
flag^=;
}
printf("%lld\n",ans);
return ;
}
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=;
struct node{
node* ch[],*fail;
int num,depth;
node(int x,int d){depth=d;memset(ch,,sizeof(ch));fail=;num=x;}
}*root;int tot=;
char str[];
node* pos[maxn];
void Add(char *c){
node* p=root;
while(*c){
int t=*c-'a';
if(p->ch[t]==NULL){p->ch[t]=new node(++tot,p->depth+);pos[tot]=p->ch[t];}
p=p->ch[t];++c;
}
}
long long f[maxn][];
long long ans=;
void getfail(){
queue<node*> q;q.push(root);
while(!q.empty()){
node* x=q.front();q.pop();
if(x!=root&&x->fail!=root)ans++;
for(int i=;i<;++i){
if(x->ch[i]){
if(x==root)x->ch[i]->fail=root;
else x->ch[i]->fail=x->fail->ch[i];
q.push(x->ch[i]);
}else{
if(x==root)x->ch[i]=root;
else x->ch[i]=x->fail->ch[i];
f[x->ch[i]->num][]++;
}
}
}
}
int main(){
int n;scanf("%d",&n);int maxlen=;
root=new node(,);pos[]=root;
for(int i=;i<=n;++i){
scanf("%s",str);int len=strlen(str);if(len>maxlen)maxlen=len;
Add(str);
}
getfail();
// for(int i=1;i<=tot;++i){
// for(int j=0;j<26;++j){
// if(pos[i]->ch[j]->num<=i){
// f[pos[i]->ch[j]->num][1]++;
// }
// }
// }
//printf("ans==%lld\n",ans);
for(int k=;k<=maxlen;++k){
for(int i=;i<=tot;++i){
if(f[i][k]==||pos[i]->depth<k)continue;
for(int j=;j<;++j){
f[pos[i]->ch[j]->num][k+]+=f[i][k];
}
if(k<=pos[i]->depth)ans+=f[i][k];
//printf("f[%d][%d]==%lld\n",i,k,f[i][k]);
}
}
printf("%lld\n",ans);
return ;
}
bzoj4502 串的更多相关文章
- BZOJ4502串——AC自动机(fail树)
题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合S,然后它们定义一个字 符串为“好”的,当且仅当它可以被分成非空的两段,其中每一段都是字符串集合S中某个字符串的前缀. 比如对于字符串集 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(62)-EF链接串加密
系列目录 前言: 这一节提供一个简单的功能,这个功能看似简单,找了一下没找到EF链接数据库串的加密帮助文档,只能自己写了,这样也更加符合自己的加密要求 有时候我们发布程序为了避免程序外的SQL链接串明 ...
- JQuery使用deferreds串行多个ajax请求
使用JQuery对多个ajax请求串行执行. HTML代码: <a href="#">Click me!</a> <div></div&g ...
- iOS 字典或者数组和JSON串的转换
在和服务器交互过程中,会iOS 字典或者数组和JSON串的转换,具体互换如下: // 将字典或者数组转化为JSON串 + (NSData *)toJSONData:(id)theData { NSEr ...
- iOS:GCD理解1(同步-异步、串行-并行)
1.并行-异步(ST1与ST2抢占资源) 1-1).获取 并行(全局)队列 ,DISPATCH_QUEUE_PRIORITY_DEFAULT 为默认优先级. dispatch_queue_t queu ...
- 关于用sql语句实现一串数字位数不足在左侧补0的技巧
在日常使用sql做查询插入操作时,我们通常会用到用sql查询一串编号,这串编号由数字组成.为了统一美观,我们记录编号时,统一指定位数,不足的位数我们在其左侧补0.如编号66,我们指定位数为5,则保存数 ...
- [LeetCode] Longest Palindrome 最长回文串
Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...
- [LeetCode] Shortest Palindrome 最短回文串
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...
- [LeetCode] Palindrome Partitioning II 拆分回文串之二
Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...
随机推荐
- ov5640介绍
1 摄像头 在各类信息中,图像含有最丰富的信息,作为机器视觉领域的核心部件,摄像头被广泛地应用在安防.探险以及车牌检测等场合.摄像头按输出信号的类型来看可以分为数字摄像头和模拟摄像头,按照摄像头图像传 ...
- 20145234黄斐《Java程序设计》第三周学习总结
教材学习内容总结 类与对象 定义:对象,与过程相对. Java中变量有2种类型,一个是基本类型,另一个则是类类型.基本类型在之前学过,本次学习类类型.使用Java撰写程序几乎都是在使用对象,要产生对象 ...
- 北京Uber优步司机奖励政策(3月16日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- python字符串的方法介绍
博文取自鱼C论坛文章: http://bbs.fishc.com/forum.php?mod=viewthread&tid=38992&extra=page%3D1%26filter% ...
- [并发并行]_[线程模型]_[Pthread线程使用模型之一管道Pipeline]
场景 1.经常在Windows, MacOSX 开发C多线程程序的时候, 经常需要和线程打交道, 如果开发人员的数量不多时, 同时掌握Win32和pthread线程 并不是容易的事情, 而且使用Win ...
- Centos7 下安装以及使用mssql
Centos7下安装以及使用Mssql,在这下面玩,主要是发现linux环境下的mysql非常的小,小到只有169M,这在windows上面,动撤几个G的安装文件,会让你直接打消使用MSSQL的勇气, ...
- Sysbench安装步骤及详情
Sysbench安装步骤及详情 Sysbench是压力测试工具,可以测试系统的CPU,内存,I/O等,也可以用于数据库的性能测试 Sysbench安装步骤: 安装具体分为Ubuntu16.04和Cen ...
- 测试模拟 白屏 / FOUC
白屏和FOUC 白屏与无样式内容闪烁(FOUC)是因为不同浏览器加载与显示页面的机制不同而造成的. 我们可以通过一个实验来进行测试和模拟白屏.FOUC的现象,让我们更好的理解白屏.FOUC. 测试de ...
- 数独:dfs+剪枝+位运算+排除冗余+优化搜索顺序(未完)
和蓝桥杯以前一个题一样,但是数据加强了,博主水平有限,没做出来,先在这里记录一下,这里正解,下面是博主的超时做法.最近准备考研,不能深入学习了. 题目描述 数独是一种传统益智游戏,你需要把一个9 × ...
- C语言 命令行参数 函数指针 gdb调试
. 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21551397 | http://www.hanshul ...