题解 P1659 【[国家集训队]拉拉队排练】
一眼可得PAM
如果没学过PAM的可以看这里:PAM学习小结
我们令PAM上多记录一个信息\(sum\),表示该节点表示串在原串上出现了多少次。
当我们处理完了\(sum\),对于长度\(len\)为奇数的节点的信息\(sum\)计入数组\(a[i]\).
\(a[i]\)为长度为\(i\)的回文子串出现次数。
\(a[i]\)降序排序后累加答案快速幂处理一下即可,不需太多点拨
重点来了
讲一下怎么处理\(sum\)
我们可以发现当一个节点\(u\)的\(sum+1\),那么\(fail[u]\)的\(sum\)也要\(+1\)
熟悉AC自动机的OIer可以敏锐的察觉到可以用拓扑排序了(例如我
建PAM的时候打个标记,最后统一一个拓扑排序向\(fail\)去更新\(sum\)即可
queue<int >q;		//in数组为fail入边数量
void tuopu(){
	for(int i=0;i<=tot;i++)if(in[i]==0)q.push(i);
	while(!q.empty()){
		int u=q.front();q.pop();
		sum[fail[u]]+=sum[u];in[fail[u]]--;
		if(in[fail[u]]==0)q.push(fail[u]);
	}
}
好像没什么问题,多一个拓扑排序就行了
但真的如此吗?
我们观察PAM和AC自动机的区别
AC自动机是建好\(Trie\)后再进行\(getFail\)的,\(fail\)的节点编号是会大于自身节点编号
而PAM不会出现这种情况,PAM\(fail\)定义不同于AC自动机,构建使用增量法,保证了\(fail\)的节点编号一定小于自身节点编号。
所以就可以不用拓扑排序了,直接一个\(for\)从后到前更新即可
for(int i=tot;i>=0;i--)sum[fail[i]]+=sum[i];
总代码:
#include<bits/stdc++.h>
#define maxn 1010001
#define ll long long
#define mod 19930726
using namespace std;
char s[maxn];
int fail[maxn],len[maxn],trie[maxn][26],trans[maxn];
long long sum[maxn];
int per,slen,tot;
long long a[maxn],K,ans=1;
int getfail(int x,int i){
	while(i-len[x]-1<0||s[i-len[x]-1]!=s[i])x=fail[x];
	return x;
}
int gettrans(int x,int i){
	while(((len[x]+2)<<1)>len[tot]||s[i-len[x]-1]!=s[i])x=fail[x];
	return x;
}
void insert(int u,int i){
	int Fail=getfail(per,i);
	if(!trie[Fail][u]){
		len[++tot]=len[Fail]+2;
		fail[tot]=trie[getfail(fail[Fail],i)][u];
		trie[Fail][u]=tot;
		if(len[tot]<=2)trans[tot]=fail[tot];
		else{
			int Trans=gettrans(trans[Fail],i);
			trans[tot]=trie[Trans][u];
		}
	}
	per=trie[Fail][u];
	sum[per]++;		//记录sum
}
ll qpow(ll n,ll m){
	ll ans=1ll;
	while(m){
		if(m&1){ans=ans*n;ans%=mod;}
		n=n*n;n%=mod;m>>=1;
	}return ans%mod;
}
int main(){
	scanf("%d%lld",&slen,&K);
	scanf("%s",s);
	fail[0]=1;len[1]=-1;tot=1;
	for(int i=0;i<slen;i++)insert(s[i]-'a',i);
	for(int i=tot;i>=1;i--)sum[fail[i]]+=sum[i];		//更新sum
	for(int i=2;i<=tot;i++)a[len[i]]+=sum[i],a[len[i]]%=mod;	//长度处理
	for(int i=slen;i>=1;i--){			//答案处理
		if(i%2==1){
			if(K>=a[i]){
				ans*=qpow(i,a[i]);ans%=mod;
				K-=a[i];
			}else{
				ans*=qpow(i,K);ans%=mod;
				K-=K;
				break;
			}
		}
	}
	if(K==0)			//判-1
	printf("%lld\n",ans%mod);
	else
	printf("-1\n");
	return 0;
}
题解 P1659 【[国家集训队]拉拉队排练】的更多相关文章
- luogu P1659 [国家集训队]拉拉队排练
		唔....话说好久没有发布题解了(手痒痒了 首先特别鸣谢lykkk大佬今天下午教我Manacher算法,甚是感谢 为了体现学习成果,写一篇蒟蒻版的题解(大佬勿喷 言归正传 题面——>在这儿 首先 ... 
- 洛谷 P1659 [国家集训队]拉拉队排练(Manacher)
		题目链接:https://www.luogu.com.cn/problem/P1659 思路: 首先跑一遍Manacher,用$cnt_i$记录长为$i$的回文串有多少个. 所记录的$cnt$并不是最 ... 
- P1659 [国家集训队]拉拉队排练
		思路 求出cnt和len之后,直接乘起来即可 代码 #include <cstdio> #include <algorithm> #include <cstring> ... 
- Manacher【p1659】 [国家集训队]拉拉队排练
		题目描述 n个女生举牌子(只含有26个小写字母,长度为n的字符串), 如果连续的一段女生,有奇数个,并且她们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体. 现在 ... 
- 【洛谷 P1659】 [国家集训队]拉拉队排练(manacher)
		题目链接 马拉车+简单膜你 #include <cstdio> #include <cstring> #include <algorithm> using name ... 
- [回文树][BZOJ2160][国家集训队]拉拉队排练
		题面 Description 艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了.拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛.所以作为拉拉队队长的楚雨荨同学知道,帮助篮 ... 
- [国家集训队]拉拉队排练 Manancher_前缀和_快速幂
		Code: #include <cstdio> #include <algorithm> #include <cstring> using namespace st ... 
- [国家集训队] 拉拉队排练 - Manacher
		用 Manacher 跑出回文串长,注意这里不需要偶数长度所以不需要对串做一些奇怪的处理 然后用前缀和搞一下,计算答案时跑快速幂即可 #include <bits/stdc++.h> us ... 
- 【题解】国家集训队礼物(Lucas定理)
		[国家集训队]礼物(扩展Lucas定理) 传送门可以直接戳标题 172.40.23.20 24 .1 答案就是一个式子: \[ {n\choose \Sigma_{i=1}^m w}\times\pr ... 
随机推荐
- React凤凰项目规范
			技术资源 基础语法 ES6 TS 框架 React Redux React-redux React-Router UmiJS Dva 组件库 AntDesign AntV 构建编译 Webpack b ... 
- Nodejs基于Express使用html模板
			express默认使用jade模板,可以配置让其支持使用ejs或html模板. 安装ejs 在项目根目录安装ejs. npm install ejs 2.引入ejs var ejs = require ... 
- iOS  模糊、精确搜索匹配功能方法总结 By HL
			字符串搜索主要用于UITableView的搜索功能的筛选,过滤,查询 下面是一些流行的搜索查询方法 一.遍历搜索 for循环 根据要求:精确搜索(判读字符串相等) 模糊搜索(字符串包含) 相关知识 ... 
- Shell双重循环、图形排列及九九乘法表
			Shell双重循环.图形排列及九九乘法表 目录 Shell双重循环.图形排列及九九乘法表 一.双重循环 1. 双重循环概述 2. 双重循环结构 二.循环特殊操作 1. exit 2. break 3. ... 
- P2678 [NOIP2015 提高组] 跳石头
			#include<bits/stdc++.h> using namespace std; int l,n,m,a[100010];//与起点的距离 bool check(int d) { ... 
- if循环&数据类型的内置方法(上)
			目录 if循环&数据类型的内置方法 for循环 range关键字 for+break for+continue for+else for循环的嵌套使用 数据类型的内置方法 if循环&数 ... 
- Vue 源码解读(2)—— Vue 初始化过程
			当学习成为了习惯,知识也就变成了常识. 感谢各位的 点赞.收藏和评论. 新视频和文章会第一时间在微信公众号发送,欢迎关注:李永宁lyn 文章已收录到 github 仓库 liyongning/blog ... 
- ELK(Elasticsearch 、 Logstash以及Kibana)
			配置日志收集系统 ELK需求背景:业务发展越来越庞大,服务器越来越多各种访问日志.应用日志.错误日志量越来越多,导致运维人员无法很好的去管理日志开发人员排查问题,需要到服务器上查日志,不方便运营人员需 ... 
- 施耐德NOE77101后门漏洞分析
			固件下载地址: GitHub - ameng929/NOE77101_Firmware 文件目录结构,这里只列出了一些主要的文件信息: ├── bin ├── ftp ├── fw ├── rdt ├ ... 
- [旧][Android] Retrofit 源码分析之 ServiceMethod 对象
			备注 原发表于2016.05.03,资料已过时,仅作备份,谨慎参考 前言 大家好,我又来学习 Retrofit 了,可能这是最后一篇关于 Retrofit 框架的文章了.我发现源码分析这回事,当时看明 ... 
