前言
学了容斥与二项式反演,也该写写题了
题目介绍
题意简介
现在有个人,要用
M
M
M步从
(
0
,
0
)
(0,0)
(0,0)跳到
(
T
x
,
T
y
)
(T_x,T_y)
(Tx,Ty),每次只能向右上方跳(即坐标值只能加),不能在原地跳
给出一些限制:给出
K
K
K个限制
k
i
k_i
ki,表示两个坐标不能同时加
k
i
k_i
ki。给出一个数
G
G
G,保证所有
k
i
k_i
ki都是
G
G
G的倍数,求方案数(模
1
0
9
+
7
10^9+7
109+7)
数据范围
T
x
,
T
y
≤
1
0
6
,
M
x
≤
T
x
,
M
y
≤
T
y
T_x,T_y\le10^6,M_x\le T_x,M_y\le T_y
Tx,Ty≤106,Mx≤Tx,My≤Ty
R
≤
1000
,
10000
≤
G
≤
50000
,
K
≤
50
R\le 1000,10000\le G\le50000,K\le50
R≤1000,10000≤G≤50000,K≤50
题解
K = 0 K=0 K=0
先考虑
K
=
0
K=0
K=0的情况
两个维度,都是
1
0
6
10^6
106级别的,一起做一定不好做
然后发现除了“两维不能同时停在原地”这个限制以外,两维是独立的
考虑对于一维,我们已知其长度
T
T
T以及单步最大距离
M
M
M
求不违反规则恰好走
x
x
x步的方案数
直接
d
p
dp
dp复杂度是
Θ
(
T
M
R
)
\Theta(TMR)
Θ(TMR)的,显然不行
我们发现至少违反
a
a
a次规则恰好走
R
R
R步的方案数很好求
设
c
a
l
c
(
a
)
calc(a)
calc(a)为至少违反
a
a
a次规则的方案数,我们发现可以选
a
a
a步,让这些步一开始就有
M
+
1
M+1
M+1的值,那么其无论再加多少都一定是违反规则的
那么就得出
c
a
l
c
(
a
)
calc(a)
calc(a)的式子:
c
a
l
c
(
a
)
=
(
R
a
)
(
T
−
(
M
+
1
)
∗
a
+
R
−
1
R
−
1
)
calc(a)=\binom{R}{a}\binom{T-(M+1)*a+R-1}{R-1}
calc(a)=(aR)(R−1T−(M+1)∗a+R−1)
预处理组合数后计算
c
a
l
c
(
a
)
calc(a)
calc(a)单次
Θ
(
1
)
\Theta(1)
Θ(1)
考虑容斥,容易发现我们要求的答案就是
∑
i
=
0
R
(
−
1
)
i
c
a
l
c
(
i
)
\sum_{i=0}^R(-1)^icalc(i)
i=0∑R(−1)icalc(i)
所以对于一维的答案的复杂度是
Θ
(
R
)
\Theta(R)
Θ(R)的,那么我们把两维都求出来
我们发现,两维的乘积的结果并不是我们想要的恰好
R
R
R步,而是至多
R
R
R步
所以我们如果要合并,我们不能直接相乘
给定
T
,
M
T,M
T,M,设
L
(
R
)
L(R)
L(R)为给至多走
R
R
R步的方案数,
E
(
R
)
E(R)
E(R)为恰好走
R
R
R步的方案数
L
(
R
)
=
∑
i
=
0
R
(
R
i
)
E
(
i
)
L(R)=\sum_{i=0}^R\binom{R}{i}E(i)
L(R)=i=0∑R(iR)E(i)
二项式反演
E
(
R
)
=
∑
i
=
0
R
(
−
1
)
R
−
i
(
R
i
)
L
(
i
)
E(R)=\sum_{i=0}^R(-1)^{R-i}\binom{R}{i}L(i)
E(R)=i=0∑R(−1)R−i(iR)L(i)
然后发现求一次
E
(
R
)
E(R)
E(R)是
Θ
(
R
2
)
\Theta(R^2)
Θ(R2)的,比较优越
K ≠ 0 K\neq0 K̸=0
然后我们考虑有
K
K
K限制的情况
我们发现我们要求的是不违反限制的情况,但是并不好求
又发现,至少违反
n
n
n次数的情况很好统计
同样考虑容斥,
g
(
x
)
g(x)
g(x)为至少违反
x
x
x次的方案数,容易发现我们要求的就是
∑
i
=
0
∞
(
−
1
)
i
g
(
i
)
\sum_{i=0}^{\infty}(-1)^ig(i)
i=0∑∞(−1)ig(i)
我们先来思考
i
i
i的范围,由于
k
i
k_i
ki都是
G
G
G的倍数,而
G
≥
10000
G\ge10000
G≥10000,所以
i
i
i的取值范围是
Θ
(
T
G
)
=
Θ
(
100
)
\Theta(\frac TG)=\Theta(100)
Θ(GT)=Θ(100)的
考虑
d
p
dp
dp来统计
g
g
g,定义
f
i
,
j
f_{i,j}
fi,j为至少违反
j
j
j次、
∑
k
=
j
∗
G
\sum k=j*G
∑k=j∗G的方案数,容易发现第二维也是
Θ
(
100
)
\Theta(100)
Θ(100)的
f
i
,
j
f_{i,j}
fi,j对答案的贡献系数即
T
x
−
j
∗
G
,
T
y
−
j
∗
G
,
x
−
i
T_x-j*G,T_y-j*G,x-i
Tx−j∗G,Ty−j∗G,x−i步并且没有任何限制的答案,通过前面
K
=
0
K=0
K=0的部分的分析可以得知这部分的复杂度是
Θ
(
M
x
)
\Theta(Mx)
Θ(Mx)的,总复杂度大概是
Θ
(
1000
∗
1000
∗
100
∗
100
)
\Theta(1000*1000*100*100)
Θ(1000∗1000∗100∗100)的
貌似能过??而且跑的飞快
当然我们要科学的复杂度,只要预处理
L
(
x
)
L(x)
L(x)即可,我们发现
T
T
T的取值因为
j
j
j的不同只有
Θ
(
100
)
\Theta(100)
Θ(100)组,步数是
Θ
(
R
)
\Theta(R)
Θ(R)的,一次处理是
Θ
(
R
)
\Theta(R)
Θ(R)的
所以总复杂度为
Θ
(
T
G
R
2
)
\Theta(\frac TGR^2)
Θ(GTR2)大约
1
0
8
10^8
108左右,再加上根本跑不满,所以很容易就过了
代码
#include<cstdio>
#include<cctype>
#include<algorithm>
namespace fast_IO
{
const int IN_LEN=10000000,OUT_LEN=10000000;
char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
//#include<ctime>
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
//template <typename T> inline void swap(T*a,T*b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
char cu=getchar();x=0;bool fla=0;
while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
const LL mod=1000000007;
inline void md(LL&x){if(x>=mod)x-=mod;}
LL fac[1000001],inv[1000001];
inline LL pow(LL x,LL y)
{
LL res=1;
for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;
return res;
}
inline LL C(LL x,LL y){return fac[x]*inv[y]%mod*inv[x-y]%mod;}
inline void init()
{
fac[0]=1;
for(rg int i=1;i<=1000000;i++)fac[i]=fac[i-1]*i%mod;
inv[1000000]=pow(fac[1000000],mod-2);
for(rg int i=1000000;i>=1;i--)inv[i-1]=inv[i]*i%mod;
}
int T,Tx,Ty,Mx,My,R,G;
int K,k[51];
LL f[101][101],g[101];
LL calc[101][1001];
inline LL solve(const int x,const int step)
{
LL res=0;
for(rg int i=0;i<=step;i++)
{
if((i&1)==(step&1))md(res+=calc[x][i]*C(step,i)%mod);
else md(res+=mod-calc[x][i]*C(step,i)%mod);
}
return res;
}
int main()
{
init();
read(Tx),read(Ty),T=min(Tx,Ty),read(Mx),read(My),read(R),read(G);
for(rg int i=0;G*i<=T;i++)
{
const int tx=Tx-G*i,ty=Ty-G*i;
for(rg int j=R;j>=0;j--)
{
if(j*Mx<tx||j*My<ty)break;
LL valx=0,valy=0;
for(rg int step=0;step<=j&&(Mx+1)*step<=tx;step++)
if(step&1)md(valx+=mod-C(j,step)*C(tx-(Mx+1)*step+j-1,j-1)%mod);
else md(valx+=C(j,step)*C(tx-(Mx+1)*step+j-1,j-1)%mod);
for(rg int step=0;step<=j&&(My+1)*step<=ty;step++)
if(step&1)md(valy+=mod-C(j,step)*C(ty-(My+1)*step+j-1,j-1)%mod);
else md(valy+=C(j,step)*C(ty-(My+1)*step+j-1,j-1)%mod);
calc[i][j]=valx*valy%mod;
}
}
read(K);
for(rg int i=1;i<=K;i++)read(k[i]);
std::sort(k+1,k+K+1);
K=std::unique(k+1,k+K+1)-k-1;
for(rg int i=1;i<=K;i++)k[i]/=G;
f[0][0]=1,g[0]=solve(0,R);
for(rg int i=1;G*i<=T;i++)
for(rg int j=0;G*j<=T;j++)
{
for(rg int kind=1;kind<=K;kind++)
if(k[kind]<=j)
md(f[i][j]+=f[i-1][j-k[kind]]);
md(g[i]+=solve(j,R-i)*f[i][j]%mod);
}
LL ans=0;
for(rg int i=0;G*i<=T;i++)
if(i&1)md(ans+=mod-g[i]*C(R,i)%mod);
else md(ans+=g[i]*C(R,i)%mod);
print(ans);
return flush(),0;
}
总结
这道题的非常巧妙,多次运用容斥与反演的技巧,值得深思
致谢:感谢yx2003在本题上对我的指导