zoukankan      html  css  js  c++  java
  • 并不对劲的loj3123:p5404[CTS2019]重复

    题目大意

    给一个小写字母串(s),问有多少个长度为(m)的小写字母串满足无限重复后存在一个子串的字典序小于(s)
    (mleq 2000;nleq 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步到某点的方案数 imes该点走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('
    ');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('
    ');
    	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;
    }
    
    一些感想

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

  • 相关阅读:
    php 经验之谈
    3)nginx的启动与停止、重启,linux配置对外端口
    git 的使用
    mysql基本定义--数据类型
    Web安全XSS
    SQL优化 csdn
    数据库隔离级别
    Web前段优化,提高加载速度 css
    jquery的height()和javascript的height总结,js获取屏幕高度
    highcharts笔记 highcharts学习 highcharts用法
  • 原文地址:https://www.cnblogs.com/xzyf/p/13046738.html
Copyright © 2011-2022 走看看