ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并不对劲的loj3123:p5404[CTS2019]重复

2020-06-04 22:02:11  阅读:280  来源: 互联网

标签:loj3123 AC return int rep fa p5404 CTS2019 include


题目大意

给一个小写字母串\(s\),问有多少个长度为\(m\)的小写字母串满足无限重复后存在一个子串的字典序小于\(s\)。
\(m\leq 2000;n\leq 2000;\)

题解

“给出一些串,求以(或不以)这些串为子串的满足某些条件的串的数量”这类问题,通常是在AC自动机上dp。
这题也可以用同样的方法,但是题目中“无限重复后存在一个子串”比较难算,所以考虑反过来算:计算无限重复后不存在一个子串的字典序小于\(s\)的串数。
这可以先把字典序大于\(s\)的串建成AC自动机,再在这个AC自动机中找长度为\(m\)的约数的环。
可以先把\(s\)建成AC自动机,然后发现对于AC自动机中一点,它接受的某一位字符时,如果这个字符大于这个点最大的出边,这个子串的字典序一定大于\(s\),可以直接走到0。
如果这个字符小于这个点最大的出边,这个子串的字典序一定小于\(s\)。
所以可以只记AC自动机中每个点最大的出边权值和它指向的点(该点能走到0的边数=26-最大边权)。
把AC自动机中的环分为两类:过0的和不过0的。
不过0的可以直接dfs:每个点只有一条不是走向0的出边,至多有1个环。注意如果环的长度为\(m\)的倍数,这个环代表了环的长度个串。
过0的:可以拆成\(0走x步到某点的方案数\times该点走m-x步到0的方案数\),然后在AC自动机上dp。

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 2007
#define LL long long
using namespace std;
void write(int x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
const int mod=998244353;
int n,m,fa[maxn],to[maxn],w[maxn],f[maxn][maxn],g[maxn][maxn],vis[maxn],len,ans;
char s[maxn];
char gc(int x){return x+'a';}
int gx(char c){return c-'a';}
int mo(int x){return x>=mod?x-mod:x;}
int getr(int u)
{
	if(!u)return 0;
	if(vis[u]){return 1;}
	vis[u]=1;
	if(getr(to[u])){len++;return u!=to[u];}
	return 0;
}
int mul(int x,int y){int res=1;while(y){if(y&1)res=(LL)res*x%mod;x=(LL)x*x%mod,y>>=1;}return res;}
int main()
{
	scanf("%d%s",&m,s+1),n=strlen(s+1);
	rep(i,2,n)
	{
		fa[i]=fa[i-1];
		while(fa[i]&&s[fa[i]+1]!=s[i])fa[i]=fa[fa[i]];
		if(s[fa[i]+1]==s[i])fa[i]++;
	}
	rep(i,0,n)
	{
		dwn(j,25,0)
		{
			int p=i;if(i==n)p=fa[i];
			while(p&&s[p+1]!=gc(j))p=fa[p];
			if(s[p+1]==gc(j)){to[i]=p+1;w[i]=25-j;break;}
		}
	}
	getr(1);
	if(m%len==0)ans=len;
	f[0][0]=1;
	rep(i,1,m)
	{
		rep(j,0,n)
		{
			f[i][to[j]]=mo(f[i][to[j]]+f[i-1][j]);
			f[i][0]=mo(f[i][0]+(LL)f[i-1][j]*w[j]%mod);
		}
	}
	rep(i,0,n)g[1][i]=w[i];
	rep(i,2,m)rep(j,0,n)g[i][j]=g[i-1][to[j]];
	rep(i,0,m)rep(j,0,n)ans=mo(ans+(LL)f[i][j]*g[m-i][j]%mod);
	write(mo(mul(26,m)-ans+mod));
	return 0;
}
一些感想

还没清空任务栈就有膜您赛了咋办!

标签:loj3123,AC,return,int,rep,fa,p5404,CTS2019,include
来源: https://www.cnblogs.com/xzyf/p/13046738.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有