problem
有一个网格,每一步可以走 ( 0 … M x , 0 … M y ) (0…Mx,0…My) (0…Mx,0…My) 中任意非零向量。
有 K K K 种向量不能走,分别是 ( k i , k i (k_i,k_i (ki,ki),其中 k i k_i ki 是 10 10 10 的倍数。
求从 ( 0 , 0 ) (0,0) (0,0) 走 R R R 步到 ( T x , T y ) (Tx,Ty) (Tx,Ty) 的方案数。对 1 0 4 + 7 10^4+7 104+7 取模。
数据范围: 1 ≤ T x , T y , M x , M y ≤ 800 1 ≤ Tx, Ty, Mx, My ≤ 800 1≤Tx,Ty,Mx,My≤800, 1 ≤ R ≤ 1600 1 ≤ R ≤ 1600 1≤R≤1600, 0 ≤ K ≤ 50 0 ≤ K ≤50 0≤K≤50, 1 ≤ k i ≤ m i n ( M x , M y ) 1 ≤ k_i ≤ min(Mx, My) 1≤ki≤min(Mx,My),且 k i   m o d   10 = 0 k_i \bmod 10 = 0 kimod10=0。
solution
算是一道比较考思维的题吧。
先不考虑非法向量, ( 0 , 0 ) (0,0) (0,0) 也先视为合法的。
我们用 f [ i ] [ x ] [ y ] f[i][x][y] f[i][x][y] 表示:走 i i i 步任意向量,走到 ( x , y ) (x, y) (x,y) 的方案数。
但是这样显然是会炸空间的,我们不妨换种表示方式,即用 f x [ i ] [ j ] f_x[i][j] fx[i][j] 表示走 i i i 步走到横坐标 ≤ j \le j ≤j 的方案数, f y [ i ] [ j ] f_y[i][j] fy[i][j] 同理。
考虑转移,用 f x [ i ] [ j ] f_x[i][j] fx[i][j] 的前缀和即可快速转移,方程如下( f y f_y fy 计算同理):
f x [ i ] [ j ] = f x [ i ] [ j − 1 ] + f x [ i − 1 ] [ j ] − f x [ i − 1 ] [ j − M x − 1 ] f_x[i][j]=f_x[i][j-1]+f_x[i-1][j]-f_x[i-1][j-Mx-1] fx[i][j]=fx[i][j−1]+fx[i−1][j]−fx[i−1][j−Mx−1]
注意一下边界。那么显然有 f [ i ] [ x ] [ y ] = f x [ i ] [ x ] × f y [ i ] [ y ] f[i][x][y]=f_x[i][x]\times f_y[i][y] f[i][x][y]=fx[i][x]×fy[i][y]。
现在考虑如何减掉非法向量。
我们用 g [ i ] [ x ] g[i][x] g[i][x] 表示:走 i i i 步非法的向量,走到 ( 10 x , 10 x ) (10x, 10x) (10x,10x) 的方案数。
显然有转移:
g [ i + 1 ] [ x + k j ] ← g [ i ] [ x ] g[i+1][x+k_j]\leftarrow g[i][x] g[i+1][x+kj]←g[i][x]
然后我们用容斥的思想,最后的答案就是:
a n s = ∑ i = 0 R ∑ j = 0 ⌊ m i n ( T x , T y ) 10 ⌋ ( − 1 ) i ( i R ) g [ i ] [ j ] × f [ R − i ] [ T x − 10 j ] [ T y − 10 j ] ans=\sum_{i=0}^R\sum_{j=0}^{\lfloor \frac{min(Tx,Ty)}{10}\rfloor} (-1)^i(^R_i)g[i][j]\times f[R-i][Tx-10j][Ty-10j] ans=i=0∑Rj=0∑⌊10min(Tx,Ty)⌋(−1)i(iR)g[i][j]×f[R−i][Tx−10j][Ty−10j]
code
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int X=805,R=1605,P=1e4+7;
int Tx,Ty,Mx,My,r,K;
int fac[R],inv[R],fx[R][X],fy[R][X],g[R][X/10];
vector<int>ban;
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
int power(int a,int b,int ans=1){
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
void prework(){
fac[0]=fac[1]=1;
for(int i=2;i<R;++i) fac[i]=mul(fac[i-1],i);
inv[R-1]=power(fac[R-1],P-2);
for(int i=R-2;~i;--i) inv[i]=mul(inv[i+1],i+1);
}
int C(int n,int m) {return mul(mul(inv[m],inv[n-m]),fac[n]);}
int F(int r,int x,int y) {return mul(dec(fx[r][x+1],fx[r][x]),dec(fy[r][y+1],fy[r][y]));}
int solve(){
prework();
int top=min(Tx,Ty)/10;
g[0][0]=1;
for(int i=1;i<=r;++i){
for(int j=0;j<ban.size();++j){
int x=ban[j]/10;
for(int k=x;k<=top;++k) g[i][k]=add(g[i][k],g[i-1][k-x]);
}
}
for(int i=1;i<=Tx+1;++i) fx[0][i]=1;
for(int i=1;i<=r;++i)
for(int j=1;j<=Tx+1;++j)
fx[i][j]=dec(add(fx[i][j-1],fx[i-1][j]),fx[i-1][j-min(j-1,Mx)-1]);
for(int i=1;i<=Ty+1;++i) fy[0][i]=1;
for(int i=1;i<=r;++i)
for(int j=1;j<=Ty+1;++j)
fy[i][j]=dec(add(fy[i][j-1],fy[i-1][j]),fy[i-1][j-min(j-1,My)-1]);
int ans=0;
for(int i=0;i<=r;++i){
int now=(i&1)?(P-C(r,i)):C(r,i);
for(int j=0;j<=top;++j)
ans=add(ans,mul(mul(now,g[i][j]),F(r-i,Tx-10*j,Ty-10*j)));
}
return ans;
}
int main(){
scanf("%d%d%d%d%d%d",&Tx,&Ty,&Mx,&My,&r,&K);
for(int i=1,x;i<=K;++i) scanf("%d",&x),ban.push_back(x);
ban.push_back(0);
printf("%d\n",solve());
return 0;
}