题解:CF2053G Naive String Splits
IvanZhang2009 · · 题解
先不考虑复杂度,就给你两个串,如何判定是否可以拼出
我们考虑如何正确地直接贪心。假设
形式化地,设
1
8
abaabaab
abaababa
这个例子里,先匹配了两次
这启发我们考虑如何反悔。是否需要反悔多次呢?仍设
于是姑且认为只需要多反悔一次即可。
对于
考虑原问题,我们可以直接暴力地做这些操作!注意到对于短串的长度为
对于公共循环节的部分,我们不需要任何 exgcd,直接枚举长串的出现次数判断整除即可,时间复杂度同长串匹配,是线性的。
可以使用 hash 或 Z 实现匹配。时间复杂度
关于把暴力匹配改成二分的做法,可以发现用
这题现在的数据还真是弱爆了,卡不掉二分,卡不掉错误的匹配。从题解看上去像是我造的但是大家其实都不太会造强数据啊,我只是稍微造了点能看的东西吧。不知道后面会不会再加强一下的。
给一个使用二分的代码,在这版数据下跑的挺快。hash 是 SA 改的,所以代码莫名其妙的。
#include<bits/stdc++.h>
using namespace std;
#define base 2310907499
#define MOD 2933256077ll
#define int long long
#define pii pair<int,int>
#define all(v) v.begin(),v.end()
#define pb push_back
#define REP(i,b,e) for(int i=(b);i<(int)(e);++i)
#define over(x) {cout<<(x)<<endl;return;}
#define lowbit(x) ((x)&(-(x)))
#define cntbit(x) __builtin_popcount(x)
#define deal(v) sort(all(v));v.erase(unique(v.begin(),v.end()),v.end())
#define lbound(v,x) lower_bound(all(v),x)-v.begin()
mt19937 sd(random_device{}());
int qpow(int a,int b,int m=MOD,int res=1){
a%=m;
while(b>0)res=(b&1)?(res*a%m):(res),a=a*a%m,b>>=1;
return res;
}
int exgcd(int x,int y,int &a,int &b){
if(y==0){
a=1;b=0;
return x;
}
int d=exgcd(y,x%y,a,b);
int z=b;
b=a-b*(x/y);
a=z;
return d;
}
int _x_,_y_;
inline int inverse(int x,int y=MOD){
exgcd(x,y,_x_,_y_);
return (_x_+y)%y;
}
int TT;
int h[1000];
uniform_int_distribution<int>rd(0,MOD-1);
struct SA{
void initbase(int n=10000000){
p1[0]=p2[0]=1;
p1[1]=base;p2[1]=inverse(base);
REP(i,2,n+1)p1[i]=p1[i-1]*p1[1]%MOD,p2[i]=p2[i-1]*p2[1]%MOD;
}
string s;
int n;
int p1[10000005],p2[10000005];
int sum[10000005];
int ask(int l,int r){
return 1ull*(sum[r+1]+MOD-sum[l])*p2[l]%MOD;
}
void build(string S){
s=S;n=s.size();
sum[0]=0;
REP(i,0,n)sum[i+1]=(sum[i]+p1[i+1]*h[s[i]]%MOD)%MOD;
}
}sa;
int n,m;
bool same(int l,int L,int len){
return sa.ask(l,l+len-1)==sa.ask(L,L+len-1);
}
bool check(int l,int r,int len,int op=1){
if(op)l+=n,r+=n;
if((r-l+1)%len)return 0;
if(r-l+1==len)return 1;
return same(l,l+len,r-l+1-len);
}
int getcopies(int x,int rt,int y,int len){
int l=1,r=(rt-x+1)/len,res=0;
if(!same(x,y,len))return 0;
while(l<=r){
int mid=(l+r)>>1;
if(check(x,x+mid*len-1,len,0))res=mid,l=mid+1;
else r=mid-1;
}
return res;
}
string t,s;
int T;
void Main() {
cin>>m>>n>>s>>t;
T-=clock();
sa.build(t+s);
T+=clock();
int f=m,g=0;
for(int i=m-1;i>=1;--i)if(check(0,m-1,i))f=i;
if(check(0,n-1,f,0)&&same(0,n,f))g=1;
REP(i,0,m-1){
int l1=0,l2=i+1,t1=i+1,t2=m-t1;
if(t1>t2)swap(l1,l2),swap(t1,t2);
if(t1%f==0&&t2%f==0){
if(!g){putchar(48);continue;}
int x=t1/f,y=t2/f,z=n/f,op=0;
for(int i=0;i*y<=z;++i)if((z-i*y)%x==0){op=1;break;}
putchar(op+48);
continue;
}
bool f=1;
int x=0,ct=getcopies(l2+n,l2+t2-1+n,l1+n,t1);
while(x<n){
int l=getcopies(x,n-1,l1+n,t1);
if(x+l*t1==n)break;
else if(l<ct){f=0;break;}
else{
x+=(l-ct)*t1;
if(x+t2<=n&&same(x,l2+n,t2)){x+=t2;continue;}
}
if(l>=ct+1&&x-t1+t2<=n&&same(x-t1,l2+n,t2)){x+=t2-t1;continue;}
f=0;break;
}
putchar(f+48);
}
puts("");
}
void TC() {
sa.initbase();
REP(i,0,200)h[i]=rd(sd);
int tc=1;
cin>>tc;
while(tc--){
Main();
cout.flush();
}
}
signed main() {
return cin.tie(0),cout.tie(0),ios::sync_with_stdio(0),TC(),0;
}