LOJ6374[SDWC2018 Day1]网格
题面:LOJ
解析
先考虑没有任何限制的情况,发现可以将两维分开来看,考虑容斥解决掉步长限制,设\(g(i)\)表示至少\(i\)步超过限制的方案数,那么有:
\[g(i)={R \choose i}{T_x-i\times(M_x+1)+R-1 \choose R-1}\]
就是保证\(i\)步超出限制,然后剩下的步数随意分配即可。
那么容斥可得:
\[Ans=\sum_{i=0}^{R}(-1)^{i} g(i)\]
那么我们可以将二维答案合并起来,就有:\(Ans=Ans_x\times Ans_y\),
但是这样的答案中有停留在原地的步数,所以其实是至多走了\(R\)步的方案数。
再一次考虑容斥消去影响,设\(g(i)\)表示至多走\(i\)步的方案数,\(f(i)\)表示恰好走\(i\)步的方案数,那么有:
\[g(R)=Ans_x\times Ans_y=\sum_{i=0}^{R} {R \choose i}f(i)\]
二项式反演,得:
\[f(R)=\sum_{i=0}^{R}(-1)^{R-i}{R \choose i}g(i)\]
那么分别计算\(g(i)\)统计答案即可。
但是题目中还有其他限制,不能走某些步长,再一次考虑容斥统计答案,设\(g(i)\)表示至少违规移动\(i\)步的方案数,\(f(i)\)表示恰好违规移动\(i\)步的方案数,那么有:
\[Ans=f(0)=\sum_{i=0}^{lim}(-1)^{i}g(i)\]
考虑如何计算\(g(i)\):因为是至少,大概就是强制\(i\)步违规乘上剩下步数随意走的方案数,发现随意走的方案数可以用上面的方法\(O(R^{2})\)计算,我们现在只用考虑如何计算强制\(i\)步违规的方案数了,设\(S(i,j)\)表示违规走\(i\)步,违规走的步长和为\(j\)的方案数,发现\(j\)是\(G\)的倍数,因此可以记录\(\frac{j}{G}\),而最多违规移动的步数最多\(lim=\frac{1e6}{1e4}=100\),这样\(S(i,j)\)的状态就只有\(O(lim^2)\)种,可以\(O(lim^3)\)提前预处理出来。
那么有:
\[g(i)=\sum_{j}S(i,j)\times Calc(T_x-j\times G,T_y-j\times G,Mx,My,R-i){R \choose i}\]
计算出\(g(i)\)就可以算出真正的答案了。复杂度是多少呢?
发现\(g(i)\)最多有\(O(lim)\)种,而计算一次\(g(i)\)的复杂度为\(O(lim\times i^2)\),那么总复杂度就是\(O(lim^2 R^2)\)。PS:这复杂度感觉过不了啊,常数小?如果算错了,请大佬指出错误。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int P=1e9+7,N=1e6;
inline int In(){
char c=getchar(); int x=0,ft=1;
for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x*ft;
}
int k[55],fac[N+5],inv[N+5],S[105][105],ans=0;
inline int power(int x,int r){
int s=1,t=x;
for(;r;r>>=1,t=1ll*t*t%P) if(r&1) s=1ll*s*t%P;
return s;
}
inline int C(int m,int n){
if(m<n) return 0;
return 1ll*fac[m]*inv[n]%P*inv[m-n]%P;
}
inline int g(int T,int M,int R){
int res=0;
for(int i=0,d=1;i<=R;++i,d=P-d)
res=(res+1ll*d*C(R,i)%P*C(T-i*(M+1)+R-1,R-1)%P)%P;
return res;
}
int Calc(int Tx,int Ty,int Mx,int My,int R){
int res=0;
for(int i=0,d=(R&1?P-1:1);i<=R;++i,d=P-d)
res=(res+1ll*d*C(R,i)%P*g(Tx,Mx,i)%P*g(Ty,My,i)%P)%P;
return res;
}
int main(){
int Tx=In(),Ty=In(),Mx=In(),My=In(),R=In();
int G=In(),K=In(),lim=(Tx<Ty?Tx:Ty)/G;
for(int i=1;i<=K;++i) k[i]=In(),k[i]/=G;
sort(k+1,k+1+K); K=unique(k+1,k+1+K)-k-1;
fac[0]=1;
for(int i=1;i<=N;++i) fac[i]=1ll*fac[i-1]*i%P;
inv[N]=power(fac[N],P-2);
for(int i=N-1;~i;--i) inv[i]=1ll*inv[i+1]*(i+1)%P;
S[0][0]=1;
for(int i=0;i<R&&i<lim;++i)
for(int j=0;j<=lim;++j) if(S[i][j])
for(int t=1;t<=K;++t)
S[i+1][j+k[t]]=(S[i+1][j+k[t]]+S[i][j])%P;
for(int i=0,d=1;i<=R&&i<=lim;++i,d=P-d)
for(int j=i;j<=lim;++j) if(S[i][j]){
ans=(ans+1ll*d*S[i][j]%P*Calc(Tx-j*G,Ty-j*G,Mx,My,R-i)%P*C(R,i)%P)%P;
}
printf("%d\n",ans);
return 0;
}