首页 > 其他分享 >[NOI2014]动物园

[NOI2014]动物园

时间:2023-06-04 20:45:03浏览次数:54  
标签:int ne NOI2014 -- ans include 动物园 define

[NOI2014] 动物园

这题看题目描述就知道一定是跟 KMP 扯上关系了。首先,如果不考虑长度超过 \(\dfrac{1}{2}\) 的限制的话,那么就很简单,每次求出一个新的 \(ne_i\) 时,如下图所示

image-20230604202339981

图中红色的表示目前对于前 \(i\) 个字符来说,最长公共前后缀为红色部分,因为两个红色部分中一定都有前后缀(即绿色部分),所以最左侧的绿色串和最右侧的是相等的。也就是说,对于 \(i\) 可以继承它的最长公共前后缀 \(ne[j]\) 的所有答案。所以如果 \(ne_i=j\),则个数 \(cnt_i=cnt_j+1\)。

现在我们并没有考虑限制,那应该怎么办呢?可以在做的时候先从 \(ne_i\) 开始往前跳,跳到第一个满足要求为止。但这样显然是可以被卡成 \(O(N^2)\),不过可以得 \(50\) 分。

#include<cstdio>
#include<cstring>
using namespace std;
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
const int N=1000010,mod=1e9+7;
int T,n,ne[N],num[N],ans;
char s[N];
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	// freopen("1.out","w",stdout);
	// ios::sync_with_stdio(0);
	// cin.tie(0);
	// cout.tie(0);
	#endif
	// Insert Code Here
	scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);
		n=strlen(s+1);
		int j=0;
		num[1]=1;
		for(int i=2;i<=n;++i){
			while(s[j+1]!=s[i]&&j)j=ne[j];
			if(s[j+1]==s[i])++j;
			ne[i]=j;
			num[i]=num[j]+1;
		}
		long long ans=1;
		for(int i=1;i<=n;++i){
			int j=ne[i];
			while(j*2>i)j=ne[j];
			ans=ans*(num[j]+1)%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

接下来考虑优化。这样跳是有很多冗余的状态的,我们可以想到并查集路径压缩的思想,但只能是一个类路径压缩的做法。我们再做一遍 KMP,使用之前求得的 ne 数组进行跳跃,由于每次 \(j\) 最多增大 \(1\),所以本来 \(38\) 行的 while 语句最多执行一次,即可以改成 if,这样就是两遍 KMP 的复杂度。但这样求得的答案会不会不是最优的呢?显然是不会的,因为你往后扩张了 \(1\),那么它先判断的肯定是最长的,反正肯定是对的。这个东西看代码就懂了。

#include<cstdio>
#include<cstring>
using namespace std;
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
const int N=1000010,mod=1e9+7;
int T,n,ne[N],num[N],ans;
char s[N];
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	// freopen("1.out","w",stdout);
	// ios::sync_with_stdio(0);
	// cin.tie(0);
	// cout.tie(0);
	#endif
	// Insert Code Here
	scanf("%d",&T);
	while(T--){
		scanf("%s",s+1);
		n=strlen(s+1);
		int j=0;
		num[1]=1;
		for(int i=2;i<=n;++i){
			while(s[j+1]!=s[i]&&j)j=ne[j];
			if(s[j+1]==s[i])++j;
			ne[i]=j;
			num[i]=num[j]+1;
		}
		int ans=1;
		j=0;
		for(int i=1;i<=n;++i){
			while(j&&s[j+1]!=s[i])j=ne[j];
			if(s[j+1]==s[i])++j;
			if(j*2>i)j=ne[j];
			ans=ans*(num[j]+1ll)%mod;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

标签:int,ne,NOI2014,--,ans,include,动物园,define
From: https://www.cnblogs.com/wscqwq/p/17456271.html

相关文章

  • 动物园
    动物园这道题的背景有些牵强,其实\(q_i\)完全没有用。首先,如果《饲养指南》中提到的规则在动物园已有的动物中存在,那么这种饲料一定会购买,那么就可以养\(p_i\)位为\(0/1\)都可以。但是如果动物园已有的动物中不存在,那么如果新动物\(p_i=1\)必定是要买新的饲料,那么不符合......
  • P4211 [LNOI2014]LCA
    \(\color{purple}\text{P4211[LNOI2014]LCA}\)解题方法可以发现一个结论:两个点到根节点的重合路径的长度即为他们\(LCA\)的深度。所以我们把\([l,r]\)之间的点到根节点路径上各加一,再查询\(z\)到根节点的路径的值之和即为\(\sum_{i=l}^{r}\text{dep}[\text{LCA}(i,z)]\)......
  • 软件开发方法动物园
    这里总结了1970年以来的软件开发方法,这些开发方法的某些特质与动物园的某些动物类似哦!,这些开发方法的某些特质与动物园的某些动物类似哦!Waterfall–1970瀑布模型是一种连续的软件开发过程……,它使得开发从需求分析、设计、实施(验证)、集成、整合和维护阶段逐步发......
  • 动物园
    动物园/*cnt代表匹配到的位置在这里的时候,已经包含匹配好的数量直接将第一个的值赋值为1就可以了这里是采取匹配两次的方法,第一次求ne数组并初始化cnt第二次是确保匹配的长度不会过大,也就是只有前面i/2个元素进行匹配,时间复杂度是o(n)两次匹配,从而确保范围*/#include<b......
  • [LNOI2014] LCA 树链剖分+离线处理+lca转化
    困困的开始了我的修炼树剖之旅途考虑怎么搞这个lca是说,习惯了倍增求lca,突然冒出这么一个东西还真不会搞那要么能一次性求很多个lca(?),要么把deep[lca(i,z)]这个东西转化......
  • P2375 [NOI2014] 动物园
    求num[i],表示1~i前缀的合法子串个数(满足前后缀相等,且不重合 #include<iostream>#include<cstring>usingnamespacestd;constintN=1e6+3,mod=1e9+7;......
  • [Ynoi2014] 等这场战争结束之后
    题传非常暴力的做法:每个点维护一颗平衡树,然后启发式合并。但是这样的暴力做法会被回溯操作卡飞天。先建出一棵操作树,将回溯操作简化为回退一次操作。思考平衡树的劣势......
  • [Ynoi2014] 置身天上之森
    题传其实做过由乃打扑克的话思路并不难。但写代码的时候把写由乃打扑克的bug全部复现了属实难蚌注意到线段树不同区间长度是\(O(\logn)\)的,因此我们对于每种长度建......
  • 洛谷P2375 [NOI2014] 动物园【题解】
    题目简要对于字符串\(......
  • 树上分块解决限制距离的树上 DP 问题([NOI2014] 购票)
    [NOI2014]购票大家好,我喜欢暴力数据结构,所以我用分块过了此题。转移方程很简单:\[f_u=\min_{d_u-d_v\leql_u}{(d_u-d_v)\timesp_u+q_u+f_v}\]\[f_u=d_u\timesp_u+q......