就是Lucas+数位DP的套路。这题和一般的数位DP相比有个特别的限制是
x1+x2+x3≤n
,类似HNOI 2007《梦幻岛宝珠》的处理方法,即相当于借位,保存当前这位剩余的数,转移时乘P传给下一位。
有3个数要填,一开始我写的是每次转移一位,转移要
O(473)
,结果T了。实际上应该每次转移一个数的一位,就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline LL getLL(){
char ch=gc(); LL res=0;
while(!('0'<=ch&&ch<='9')) ch=gc();
while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=gc();
return res;
}
const int maxn=20,P=47;
int _test,a1[maxn],a2[maxn],a3[maxn],R1[maxn],R2[maxn],R3[maxn],N[maxn];
int f[maxn][3][2][2][2][3*47+5];
LL n,L[4],R[4];
int ans,fac[P+5],inv[P+5],fac_inv[P+5];
inline int C(int n,int m){ if(n<m) return 0; return fac[n]*fac_inv[m]%P*fac_inv[n-m]%P; }
int Solve(LL x,LL y,LL z){
memset(f,0,sizeof(f));memset(R1,0,sizeof(R1));memset(R2,0,sizeof(R2));memset(R3,0,sizeof(R3));
R1[0]=0; do R1[++R1[0]]=x%P, x/=P; while(x);
R2[0]=0; do R2[++R2[0]]=y%P, y/=P; while(y);
R3[0]=0; do R3[++R3[0]]=z%P, z/=P; while(z);
int m=max(max(N[0],R1[0]),max(R2[0],R3[0]));
f[m+1][2][0][0][0][0]=1;
for(int i=m+1;i>=1;i--)
for(int j=0;j<=2;j++) if(!(i==1&&j==2))
for(int j1=0;j1<=1;j1++)
for(int j2=0;j2<=1;j2++)
for(int j3=0;j3<=1;j3++)
for(int k=0;k<=47*3;k++) if(f[i][j][j1][j2][j3][k]){
int _f=f[i][j][j1][j2][j3][k];
if(j==0){
for(int x=0;x<=(j2?P-1:R2[i]);x++) if(x<=k)
(f[i][1][j1][j2|(x<R2[i])][j3][k-x]+=_f*C(a2[i],x))%=P;
}
if(j==1){
for(int x=0;x<=(j3?P-1:R3[i]);x++) if(x<=k)
(f[i][2][j1][j2][j3|(x<R3[i])][k-x]+=_f*C(a3[i],x))%=P;
}
if(j==2){
for(int x=0;x<=(j1?P-1:R1[i-1]);x++) if(x<=k*P+N[i-1])
(f[i-1][0][j1|(x<R1[i-1])][j2][j3][min(k*P+N[i-1]-x,47*3)]+=_f*C(a1[i-1],x))%=P;
}
}
int res=0;
for(int j1=0;j1<=1;j1++)
for(int j2=0;j2<=1;j2++)
for(int j3=0;j3<=1;j3++)
for(int k=0;k<=47*3;k++) (res+=f[1][2][j1][j2][j3][k])%=P;
return res;
}
int main(){
freopen("jsk445.in","r",stdin);
freopen("jsk445.out","w",stdout);
fac[0]=1; for(int i=1;i<=P;i++) fac[i]=fac[i-1]*i%P;
inv[1]=1; for(int i=2;i<=P;i++) inv[i]=(P-P/i)*inv[P%i]%P;
fac_inv[0]=1; for(int i=1;i<=P;i++) fac_inv[i]=fac_inv[i-1]*inv[i]%P;
_test=getLL();
while(_test--){
memset(N,0,sizeof(N));memset(a1,0,sizeof(a1));memset(a2,0,sizeof(a2));memset(a3,0,sizeof(a3));
LL x,y,z; x=getLL(),L[1]=getLL(),R[1]=getLL(),y=getLL(),L[2]=getLL(),R[2]=getLL(),z=getLL(),L[3]=getLL(),R[3]=getLL(),n=getLL();
N[0]=0; do N[++N[0]]=n%P, n/=P; while(n);
a1[0]=0; do a1[++a1[0]]=x%P, x/=P; while(x);
a2[0]=0; do a2[++a2[0]]=y%P, y/=P; while(y);
a3[0]=0; do a3[++a3[0]]=z%P, z/=P; while(z);
ans=Solve(R[1],R[2],R[3]);
(ans-=Solve(L[1]-1,R[2],R[3]))%=P;
(ans-=Solve(R[1],L[2]-1,R[3]))%=P;
(ans-=Solve(R[1],R[2],L[3]-1))%=P;
(ans+=Solve(L[1]-1,L[2]-1,R[3]))%=P;
(ans+=Solve(L[1]-1,R[2],L[3]-1))%=P;
(ans+=Solve(R[1],L[2]-1,L[3]-1))%=P;
(ans-=Solve(L[1]-1,L[2]-1,L[3]-1))%=P;
printf("%d\n",(ans+P)%P);
}
return 0;
}