蓝桥杯 质数行者
题目描述
小蓝在玩一个叫质数行者的游戏。
游戏在一个 n×m×w 的立体方格图上进行,从北到南依次标号为第 1 行到
第 n 行,从西到东依次标号为第 1 列到第 m 列,从下到上依次标号为第 1 层到第 w 层。
小蓝要控制自己的角色从第 1 行第 1 列第 1 层移动到第 n 行第 m 列第 w层。每一步,他可以向东走质数格、向南走质数格或者向上走质数格。每走到一个位置,小蓝的角色要稍作停留。
在游戏中有两个陷阱,分别为第 r 1 行第 c 1 列第 h 1 层和第 r 2 行第 c 2 列第h2 层。这两个陷阱的位置可以跨过,但不能停留。也就是说,小蓝不能控制角色某一步正好走到陷阱上,但是某一步中间跨过了陷阱是允许的。
小蓝最近比较清闲,因此他想用不同的走法来完成这个游戏。所谓两个走法不同,是指小蓝稍作停留的位置集合不同。
请帮小蓝计算一下,他总共有多少种不同的走法。
提示:请注意内存限制,如果你的程序运行时超过内存限制将不得分。
输入描述
输入第一行包含两个整数 n, m, wn,m,w,表示方格图的大小。
第二行包含 66 个整数,r_1, c_1, h_1, r_2, c_2, h_2r1,c1,h1,r2,c2,h2,表示陷阱的位置。
其中有 ,1 ≤ n, m, w ≤ 1000,1 ≤ r_1,r_2 ≤ n, 1 ≤ c_1, c_2 ≤ m,1 ≤ h_1, h_2 ≤ w1≤n,m,w≤1000,1≤r1,r2≤n,1≤c1,c2≤m,1≤h1,h2≤w,陷阱不在起点或终点,两个陷阱不同。
输出描述
输出一行,包含一个整数,表示走法的数量。答案可能非常大,请输出答案除以 10^9+7 的余数。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define N 2005
#define ll long long
ll vis[N];
ll prime[N];
ll jie[N],S[N][N];
ll tot;
ll inv(ll x){
ll p=mod-2;
ll y=1;
while(p){
if(p&1){
y=(y*x)%mod;
}
x=(x*x)%mod;
p>>=1;
}
return y;
}
ll dp[N][N];
void preparation(ll n,ll m,ll w){
if(n<1||m<1||w<1)return ;
int nm=max(n+m,w);
jie[0]=1;
for(int i=1;i<=nm;i++)jie[i]=(jie[i-1]*i)%mod;
for(int i=0;i<=nm;i++){
for(ll j=0;j<=i;j++){
S[i][j]=((jie[i+j]*inv(jie[i]))%mod*inv(jie[j]))%mod;
S[j][i]=S[i][j];
}
}
int mm=max(max(n,m),w);
for(int i=2;i<=mm;i++){
if(!vis[i])prime[++tot]=i;
for(ll j=1;prime[j]*i<=mm&&j<=tot;j++){
vis[prime[j]*i]=1;
}
}dp[1][0]=1;
for(int i=2;i<=mm;i++){
for(int k=1;k<=(i-1)/2;k++){
for(int j=1;j<=tot&&prime[j]<i;j++){
dp[i][k]=(dp[i][k]+dp[i-prime[j]][k-1])%mod;
}
}
}
}
ll X[N],Y[N],Z[N],XY[N*2],XYZ[N*3];
ll find(ll x,ll y,ll z){
ll totx=(x-1)/2,toty=(y-1)/2,totz=(z-1)/2,ans=0;
for(int i=0;i<=totx;i++){
X[i]=dp[x][i];
}
for(int i=0;i<=toty;i++){
Y[i]=dp[y][i];
}
for(int i=0;i<=totz;i++){
Z[i]=dp[z][i];
}
for(int i=0;i<=totx+toty;i++)XY[i]=0;
for(int i=0;i<=totx;i++){
for(int j=0;j<=toty;j++){
XY[i+j]+=((X[i]*Y[j])%mod*S[i][j])%mod;
XY[i+j]=XY[i+j]%mod;
}
}
for(int i=0;i<=totx+toty+totz;i++)XYZ[i]=0;
for(int i=0;i<=totx+toty;i++){
for(ll j=0;j<=totz;j++){
XYZ[i+j]+=(((XY[i]*Z[j])%mod)*S[i][j])%mod;
XYZ[i+j]=XYZ[i+j]%mod;
}
}
for(ll i=0;i<=totx+toty+totz;i++)ans=(ans+XYZ[i])%mod;
return ans;
}
ll n,m,w,R1,R2,C1,C2,H1,H2;
int main(){
scanf("%lld%lld%lld",&n,&m,&w);
scanf("%lld%lld%lld%lld%lld%lld",&R1,&C1,&H1,&R2,&C2,&H2);
if(R1>R2||C1>C2||H1>H2){
swap(R1,R2);swap(C1,C2);swap(H1,H2);
}
preparation(n,m,w);
ll ans1=find(n,m,w);
ll ans2=(find(R1,C1,H1)*find(n-R1+1,m-C1+1,w-H1+1))%mod;
ll ans3=(find(R2,C2,H2)*find(n-R2+1,m-C2+1,w-H2+1))%mod;
ll ans4=(((find(R1,C1,H1)*find(R2-R1+1,C2-C1+1,H2-H1+1))%mod)*find(n-R2+1,m-C2+1,w-H2+1))%mod;
printf("%lld\n",(((ans1-ans2 + mod) % mod -ans3 + mod) % mod + ans4 +mod)%mod);
}