UOJ传送门
LOJ传送门
洛谷传送门
垃圾BZOJ不知道是不是放错数据了,居然连标算都A不了
题解:
这道题最扯的地方在于,除了IO优化,没有任何板子可以拿上来。
也就是说,这是一道纯思维难度加代码难度的题。与你板子熟不熟练没有任何关系。
然而推出结论后,正解相当暴力。
设 m x = max ( n , k ) mx=\max(n,k) mx=max(n,k),则我们维护所有 2 m x 2^{mx} 2mx个不同的长为 m x mx mx的 01 01 01串在这个大串里面的出现次数。
发现每次平方就是把所有项的次数乘上 2 2 2,因为交叉项会正反算两次,模2意义下就没有贡献了。
然后我就不会了。。。滚去orz标算了
但是我也不知道我哪里写挂掉了,需要对于询问前缀长度小于
n
n
n的情况进行特殊处理,不然过不了UOJ的hack数据。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc getchar
#define cs const
#define int ll
template<typename T>
inline T get(){
char c;
while(!isdigit(c=gc()));T num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int getint(){return get<int>();}
inline ll getll(){return get<ll>();}
inline int gs(){char c;while(!isdigit(c=gc()));return c^48;}
using std::cerr;
using std::cout;
cs int N=1<<19|1;
int t1[N],t2[N],T1[N],T2[N];
ll F[N],G[N],S,SS;
int n,k,mx;
ll m,L,R;
int start,token;
bool st[60];int top;
ll Lim[60];
bool a[N],b[N],c[N];
inline ll solve(ll lim){
if(lim==-1)return 0;
std::bitset<128> o=start,p,t;o<<=mx+1;
ll all=n,*f=F,*g=G;
int *d1,*d2,del;bool R;
if(lim<=n){
int n=::n,token=::token;ll m=::m;
a[all=0]=1;token>>=mx-k;
for(int re i=0;i<=n;++i)b[i]=(start>>i)&1;
while(m){
if(m&1){
for(int re i=all+n;~i;--i)c[i]=0;
for(int re i=0;i<=all;++i)
for(int re j=0;j<=n;++j)c[i+j]^=a[i]&b[j];
all=std::min(all+n,lim);
for(int re i=0;i<=lim;++i)a[i]=c[i];
}
for(int re i=n<<1;i>n;--i)b[i]=0;
for(int re i=n<<1;~i;--i)b[i]=i&1?0:b[i>>1];
n=std::min(n<<1,(int)lim);
m>>=1;
}
int ans=0;
for(int re i=0;i<=all;++i){
ll p=0;
for(int re j=0;j<=k;++j){
p=p<<1|(i<j?0:a[i-j]);
}
ans+=p==token;
}
return ans;
}
Lim[1]=lim;
for(int re i=2;i<60;++i)Lim[i]=Lim[i-1]+1>>1;
for(int re i=0;i<=all;++i)++f[start<<(mx-i)&S];
ll tmp=m;top=0;
while(tmp>1)st[++top]=tmp&1,tmp>>=1;
while(top){
std::swap(f,g);lim=Lim[top];
(R=st[top--])?(d1=T1,d2=T2):(d1=t1,d2=t2);
for(int re s=0;s<=S;++s)if(g[s])f[d1[s]]+=g[s],f[d2[s]]+=g[s],g[s]=0;
p=0;for(int re i=0;i<=(mx<<1|1);++i)p[i<<1]=o[i];
all=(all<<1)+(R?mx:0);del=std::max(0ll,all-lim);
switch(R){
case 1:{o=0;
for(int re i=0;i<=mx;++i)if(start&(1<<i))o^=p<<i;
for(int re i=1;i<=mx;++i){
t=o>>((mx<<2)+3-i);t&=S;
f[t.to_ulong()]++;
}
for(int re i=0;i<del;++i){
t=o>>((mx<<2)+2-i);t&=S;
f[t.to_ulong()]--;
}
(o>>=mx*3+1-del)&=SS;
break;
}
case 0:{
for(int re i=0;i<del;++i){
t=p>>(mx*3+2-i);t&=S;
f[t.to_ulong()]--;
}
o=p>>((mx<<1|1)-del);o&=SS;
break;
}
}
--f[0];
all-=del;
}
ll ans=0;
for(int re i=0;i<(1<<mx-k);++i)ans+=f[i|token];
for(int re s=0;s<=S;++s)f[s]=0;
return ans;
}
inline void solve(){
n=getint(),m=getll();
k=getint()-1,R=n*m-getll()+1,L=n*m-getll()+1;
mx=std::max(n,k),S=(1<<mx+1)-1,SS=(1ll<<(mx+1<<1))-1;
start=token=0;
for(int re i=0;i<=n;++i)start|=gs()<<mx-i;
for(int re i=0;i<=k;++i)token|=gs()<<mx-i;
if(R-L+1<k){
cout<<"0\n";
return ;
}
for(int re s=0;s<=S;++s){
ll to=0,p=0;
for(int re i=0;i<=mx;++i)to|=(s&(1ll<<i))<<i;
t1[s]=to>>(mx-1)&S;
t2[s]=to>>mx&S;
for(int re i=0;i<=mx;++i)if(start&(1<<i))p^=to<<i;
T1[s]=p>>(mx-1)&S;
T2[s]=p>>mx&S;
}
ll ans1=solve(R);
ll ans2=solve(L-1+k);
cout<<ans1-ans2<<"\n";
}
signed main(){
#ifdef zxyoi
freopen("poly.in","r",stdin);//freopen("poly.out","w",stdout);
#endif
int T=getint();
while(T--)solve();
return 0;
}