LOJ6374[SDWC2018 Day1]网格

LOJ6374[SDWC2018 Day1]网格

题面:LOJ

解析

这是大佬的题解

先考虑没有任何限制的情况,发现可以将两维分开来看,考虑容斥解决掉步长限制,设(g(i))表示至少(i)步超过限制的方案数,那么有:

[g(i)={R choose i}{T_x-i imes(M_x+1)+R-1 choose R-1} ]

就是保证(i)步超出限制,然后剩下的步数随意分配即可。
那么容斥可得:

[Ans=sum_{i=0}^{R}(-1)^{i} g(i) ]

那么我们可以将二维答案合并起来,就有:(Ans=Ans_x imes Ans_y)
但是这样的答案中有停留在原地的步数,所以其实是至多走了(R)步的方案数。
再一次考虑容斥消去影响,设(g(i))表示至多走(i)步的方案数,(f(i))表示恰好走(i)步的方案数,那么有:

[g(R)=Ans_x imes 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) imes Calc(T_x-j imes G,T_y-j imes G,Mx,My,R-i){R choose i} ]

计算出(g(i))就可以算出真正的答案了。复杂度是多少呢?
发现(g(i))最多有(O(lim))种,而计算一次(g(i))的复杂度为(O(lim imes 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
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/pkh68/p/10549078.html