先考虑假设知道了棋盘长什么样,怎么计算每个篮子会接到多少个球
对于一个格子
(i,j)
(
i
,
j
)
,若我们知道会有
x
x
个球滚到这个格子,那么一定会有个球走到这个格子指的方向,
⌊x2⌋
⌊
x
2
⌋
个球走到另一个方向
换句话说,只有
xmod2
x
mod
2
个球和这个格子的方向有关,其他的球预先已经知道了要走到哪里
当我们知道了棋盘的样子,就可以递推得到每个篮子接到的球数
当我们不知道棋盘长什么样的时候,因为有一些球的走向是和棋盘无关的,我们可以先在棋盘上做一个递推,把不确定方向的球留在棋盘上,得到一个01棋盘,由此可以发现虽然询问的 L,R L , R 很大,但其实有值的答案区间不超过nm
然后对这个棋盘做一个很暴力的轮廓线DP,状态为经过每一条轮廓线从已知区域到未知区域的球数和当前篮子已经接住的球数,走每条轮廓线出来的球不可能>50,可以用一个51进制的数存,写个hash表,大力DP,因为出题人实测状态数很少,这样做跑的过….
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 20;
const int B = 51;
const int hm = 233333;
const int mod = 998244353;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
inline void dec(int &a,const int &b){a-=b;if(a<0)a+=mod;}
struct Hash_Table
{
int cnt;
int nex[hm<<2],ci[hm<<2],cs[hm<<2]; ll cy[hm<<2];
void init()
{
cnt=hm-1;
memset(nex,-1,sizeof nex);
}
void clear()
{
while(cnt>hm)
{
nex[cnt]=-1,ci[cnt]=cs[cnt]=cy[cnt]=-1;
cnt--;
}
for(int i=0;i<hm;i++) nex[i]=-1,ci[i]=cs[i]=cy[i]=-1;
}
void ins(int x,ll y,int i,int s)
{
if(ci[x]==-1) { ci[x]=i,cs[x]=s,cy[x]=y; return; }
int la;
for(;x!=-1;la=x,x=nex[x]);
nex[la]=x=++cnt;
ci[x]=i,cs[x]=s,cy[x]=y;
}
int find_(int x,ll y,int s)
{
for(;x!=-1;x=nex[x]) if(cy[x]==y&&s==cs[x])
return ci[x];
return -1;
}
}h;
ll pwb[maxn];
struct node
{
ll x; int s;
int num;
}f[2][510000]; int len[2],now;
int n,m; ll K;
int rel[maxn],rec[maxn];
char str[maxn];
int w[maxn][maxn]; ll fn[maxn][maxn];
int ans[maxn*maxn],ansu; ll base;
void Solve()
{
fn[1][1]=K; ansu=w[1][1]=fn[1][1]&1ll;
for(int i=1;i<=n;i++) for(int j=(i==1?2:1);j<=m;j++)
{
fn[i][j]=fn[i][j-1]/2ll+fn[i-1][j]/2ll;
w[i][j]=fn[i][j]&1ll;
ansu+=w[i][j];
}
for(int i=1;i<=n;i++) if(rel[i]) base+=fn[i][m]/2ll;
for(int i=1;i<=m;i++) if(rec[i]) base+=fn[n][i]/2ll;
pwb[0]=1ll;
for(int i=1;i<=11;i++) pwb[i]=pwb[i-1]*(ll)B;
h.init();
int now=0; len[now]=1; f[now][1]=(node){0,0,1};
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
len[now=!now]=0; h.clear();
for(int k=1;k<=len[!now];k++)
{
ll x=f[!now][k].x; int s=f[!now][k].s,temp=f[!now][k].num;
int c1=x/pwb[j-1]%B,c2=x/pwb[m]%B,cw=c1+c2+w[i][j];
int cw1=cw/2+(cw&1),cw0=cw/2;
ll nx; int ns,ni;
nx=x+pwb[j-1]*(cw0-c1)+pwb[m]*((j==m?0:cw1)-c2); ns=s+cw0*(i==n&&rec[j])+cw1*(j==m&&rel[i]);
ni=h.find_(nx%hm,nx,ns);
if(ni==-1)
{
ni=++len[now]; f[now][ni].x=nx,f[now][ni].s=ns,f[now][ni].num=0;
h.ins(nx%hm,nx,ni,ns);
}
add(f[now][ni].num,temp);
nx=x+pwb[j-1]*(cw1-c1)+pwb[m]*((j==m?0:cw0)-c2); ns=s+cw1*(i==n&&rec[j])+cw0*(j==m&&rel[i]);
ni=h.find_(nx%hm,nx,ns);
if(ni==-1)
{
ni=++len[now]; f[now][ni].x=nx,f[now][ni].s=ns,f[now][ni].num=0;
h.ins(nx%hm,nx,ni,ns);
}
add(f[now][ni].num,temp);
}
}
}
for(int i=1;i<=len[now];i++)
add(ans[f[now][i].s],f[now][i].num);
for(int i=1;i<=ansu;i++) add(ans[i],ans[i-1]);
}
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
scanf("%d%d%lld",&n,&m,&K);
scanf("%s",str); for(int i=0;i<n;i++) rel[i+1]=str[i]-'0';
scanf("%s",str); for(int i=0;i<m;i++) rec[i+1]=str[i]-'0';
Solve();
int q;scanf("%d",&q);
while(q--)
{
ll l,r; scanf("%lld%lld",&l,&r);
l-=base; r-=base;
if(l>ansu||r<0) puts("0");
else
{
r=min(r,(ll)ansu);
int re=ans[r]; if(l>0) dec(re,ans[l-1]);
printf("%d\n",re);
}
}
return 0;
}