Om Nom and Necklace CodeForces - 526D KMP处理循环节 + 数学取整运算证明

博客探讨了如何判断一个字符串的每个前缀是否符合ABABA形式,其中A和B的数量是固定的。通过分析字符串的循环节和使用KMP算法,解释了如何检查满足条件的前缀。文章特别强调了数学取整运算在确定循环节个数中的应用。
摘要由CSDN通过智能技术生成

题意:求每个前缀是否是ABABA 的形式。(其中A有k+1个,B有k个,AB均可为空)

对于一个前缀字符串i:

令S=AB

则可看成:SSSSA。

若满足S的个数为k,则满足题意。

对于前缀字符串i:其最小循环节e长度为:i-nxt[i], 改字符串可以看做:eeeex

如果若干个e拼凑成一个S,使得S的数量为k,则满足题意。

即:

{\frac{i}{j*e}}==k(下取整)构成:AB AB AB AB A

或者当i%e==0时,

{\frac{i}{j*e}}==k+1,此时B为空。

 

第二种情况很好求。

关键是第一种:

我们知道  [x](下取整)=k  则有: k <= x < k+1

则有:  k<=\frac{i}{j*e}<k+1

即:\frac{i}{(k+1)*e}<j<=\frac{i}{k*e}

则可O1处理这个判断:

 



#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e6+7;
/*
int head[M],cnt=1;
void init(int n){cnt=1;for(int i=0;i<=n;i++)head[i]=0;}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
int n,k;
char s[M];
int nxt[M];
bool ck(int i,int e)//e是最小循环节的长度
{
	//SSSA
	//k+1个A,k个B
	//1:i/e  = j * k  = > k<= i/(j*e) < k+1
	//= >  i/(e*(k+1))  < j <=i/(e*k)
	if(i/e/k>i/e/(k+1)) return true;
	//2: A='0',即 i%e==0,  且 i/e = j*k 
	if(i%e==0&&(i/e%k==0||i/e%(k+1)==0))return true;
	return false;
 } 
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
  	cin>>n>>k;
  	cin>>s+1;
  	nxt[1]=0;
  	for(int i=2,j=0;i<=n;i++)
  	{
  		while(j&&s[i]!=s[j+1])j=nxt[j];
  		if(s[i]==s[j+1])j++;
		nxt[i]=j;
	}
	//ABABA   令S=AB  SSSA
	//对于前缀i,len=i-ntx[i],  则前缀i可以表示为:SSSA ,其中S的长度为len,A是S的前缀 (nxt[i]的性质)
	for(int i=1;i<=n;i++)
	{
	//	cout<<i<<"  - "<<i-nxt[i]<<"      "<<ck(i,i-nxt[i])<<endl;
		cout<<ck(i,i-nxt[i]);
	}
	//	cout<<ck(i,i-nxt[i]);
	cout<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值