题解 CF1979D Fixing a Binary String
cjh20090318 · · 题解
观察不出来性质,我选择了最朴素的方法。
题意
定义一个字符串是
定义一次操作为选择一个
你需要找到一个整数
分析
根据定义可以得到
于是对应两种字符串,直接枚举
枚举
注意事项
本题是 CodeForces 上的一道题,由于 Hack 机制的存在,强烈不建议大家写固定模数哈希(双哈希也不建议),所以我选择了随机双底数自然溢出前后缀哈希。
代码
//the code is from chenjh
#include<cstdio>
#include<cstdlib>
#include<random>
#define MAXN 100005
using namespace std;
typedef unsigned int UI;
typedef unsigned long long ULL;
int n,k;
mt19937 mtrd(random_device{}());
const UI P[]={61,3881,6907,19260817,29050993,998244353};//底数列表。
UI p1,p2;
ULL pn1[MAXN],pn2[MAXN],hsl[2][MAXN],hsr[2][MAXN],htl[2][MAXN],htr[2][MAXN];
char s[MAXN],t[MAXN];
void init(ULL hsl[][MAXN],ULL hsr[][MAXN],char *s,const int n){//初始化前后缀哈希。
hsl[0][0]=hsl[1][0]=0;
for(int i=1;i<=n;i++)
hsl[0][i]=hsl[0][i-1]*p1+s[i]-'0'+1,hsl[1][i]=hsl[1][i-1]*p2+s[i]-'0'+1;//前缀哈希。
hsr[0][n+1]=hsr[1][n+1]=0;
for(int i=n;i>0;--i)
hsr[0][i]=hsr[0][i+1]*p1+s[i]-'0'+1,hsr[1][i]=hsr[1][i+1]*p2+s[i]-'0'+1;//后缀哈希。
}
ULL qryl(ULL *hs,ULL *pn,const int l,const int r){//查询前缀。
return hs[r]-hs[l-1]*pn[r-l+1];
}
ULL qryr(ULL *hs,ULL *pn,const int l,const int r){//查询后缀。
return hs[l]-hs[r+1]*pn[r-l+1];
}
void solve(){
scanf("%d %d %s",&n,&k,s+1);
init(hsl,hsr,s,n);//初始化 s 的哈希值。
bool f=0;
for(int i=1;i<=n;f^=!(i++%k)) t[i]=f|'0';//0 开头的 k-proper 序列。
init(htl,htr,t,n);
for(int p=1;p<=n;p++)
if(qryl(hsl[0],pn1,p+1,n)==qryl(htl[0],pn1,1,n-p)&&qryl(hsl[1],pn2,p+1,n)==qryl(htl[1],pn2,1,n-p)
&&qryr(hsr[0],pn1,1,p)==qryl(htl[0],pn1,n-p+1,n)&&qryr(hsr[1],pn2,1,p)==qryl(htl[1],pn2,n-p+1,n)){
printf("%d\n",p);return;
}//判断 s[p+1:n]=t[1:n-p] 和 s[p:1]=t[n-p+1:n]。
f=1;
for(int i=1;i<=n;f^=!(i++%k)) t[i]=f|'0';//1 开头的 k-proper 序列。
init(htl,htr,t,n);
for(int p=1;p<=n;p++)
if(qryl(hsl[0],pn1,p+1,n)==qryl(htl[0],pn1,1,n-p)&&qryl(hsl[1],pn2,p+1,n)==qryl(htl[1],pn2,1,n-p)
&&qryr(hsr[0],pn1,1,p)==qryl(htl[0],pn1,n-p+1,n)&&qryr(hsr[1],pn2,1,p)==qryl(htl[1],pn2,n-p+1,n)){
printf("%d\n",p);return;
}//判断条件同上。
puts("-1");
}
int main(){
p1=P[mtrd()%6];
do p2=P[mtrd()%6];while(p1==p2);//随机选择双底数。
*pn1=*pn2=1;
for(int i=1;i<MAXN;i++) pn1[i]=pn1[i-1]*p1,pn2[i]=pn2[i-1]*p2;//预处理幂次。
int T;scanf("%d",&T);
while(T--) solve();
return 0;
}