解题思路
首先,考虑Ca+b−kaC_{a+b-k}^aCa+b−ka的组合意义,相当于是在二维平面上,从(a,b)(a,b)(a,b)走到(0,k)(0,k)(0,k),每次可以向下或者向左走的方案数的方案数
因此,原题等价于对于k=0……n−1,k=0……n-1,k=0……n−1,求所有点到(0,k)(0,k)(0,k)的方案数之和。
首先可以把坐标系水平翻转一下,这样的话就相当于每次可以向左或者向上走,水平翻转是指(x,y)(x,y)(x,y)变成(x,n−1−y)(x,n-1-y)(x,n−1−y),这样做是为了方便卷积。
接下来,我们对x这一维分块,取一个整数B,然后设dp[i][j]dp[i][j]dp[i][j],表示从所有点走到(iB,j)(iB,j)(iB,j)的方案数。
不过这样子的话会算重,于是我们换一下,设dp[i][j]dp[i][j]dp[i][j]表示从所有点走到(iB,j)(iB,j)(iB,j),且最后一步向左走的方案数。
首先,考虑如果iBiBiB到(i+1)B(i+1)B(i+1)B这段区间内没有点的情况。
我们可以写出一个dpdpdp式子:
dp[i][j]=∑kdp[i+1][k]Cj−k+B−1j−kdp[i][j]=\sum_{k}dp[i+1][k]C_{j-k+B-1}^{j-k}dp[i][j]=k∑dp[i+1][k]Cj−k+B−1j−k减一是因为最后一步钦定了。
我们可以把它看成两个多项式卷积的形式,其中,第二个多项式为CB−10,CB−1+11,CB−1+22……C_{B-1}^0,C_{B-1+1}^1,C_{B-1+2}^2……CB−10,CB−1+11,CB−1+22……
根据经典结论,Ci0,Ci+11……C_i^0,C_{i+1}^1……Ci0,Ci+11……的OGF为1(1−x)i+1\frac{1}{(1-x)^{i+1}}(1−x)i+11
因此该多项式的OGF为1(1−x)B\frac{1}{(1-x)^{B}}(1−x)B1
然后考虑新加的点,那么就会有dp式子:
dp[i][j]=dp[i][j]+Cj−a+l−1j−adp[i][j]=dp[i][j]+C_{j-a+l-1}^{j-a}dp[i][j]=dp[i][j]+Cj−a+l−1j−a,其中l表示这个点到x=Bix=Bix=Bi这条直线的距离。
这种转移也可以写成生成函数:
xb1(1−x)lx^b\frac{1}{(1-x)^{l}}xb(1−x)l1
综合一下,设F(i,x)=dp[i]F(i,x)=dp[i]F(i,x)=dp[i]的生成函数.
那么F(i,x)=F(i−1,x)×1(1−x)B+∑ixb1(1−x)lF(i,x)=F(i-1,x)\times \frac{1}{(1-x)^{B}}+\sum_ix^b\frac{1}{(1-x)^{l}}F(i,x)=F(i−1,x)×(1−x)B1+i∑xb(1−x)l1
不过如果就是这个样子的话,那么后面的部分是O(n2)O(n^2)O(n2)的
乘法分配律:
F(i,x)=(F(i−1,x)+∑ixb1(1−x)l−B)×1(1−x)BF(i,x)=(F(i-1,x)+\sum_ix^b\frac{1}{(1-x)^{l-B}})\times \frac{1}{(1-x)^{B}}F(i,x)=(F(i−1,x)+i∑xb(1−x)l−B1)×(1−x)B1
F(i,x)=(F(i−1,x)+∑ixb(1−x)B−l)×1(1−x)BF(i,x)=(F(i-1,x)+\sum_ix^b(1-x)^{B-l})\times \frac{1}{(1-x)^{B}}F(i,x)=(F(i−1,x)+i∑xb(1−x)B−l)×(1−x)B1
这样做的好处是,前面加的部分只需要O(B)O(B)O(B)就可以计算了。
接着我们只需要展开(1−x)B−l,1(1−x)B(1-x)^{B-l}, \frac{1}{(1-x)^{B}}(1−x)B−l,(1−x)B1然后做卷积就行了。
前面可以二项式定理展开(注意x前面是符号),后面直接套用上边的结论展开就行了。
时间复杂度O(nB+n(n/B)logn)O(nB+n(n/B)logn)O(nB+n(n/B)logn),取B=(nlogn)B=\sqrt (nlogn)B=(nlogn)
最后因为我们的dp钦定最后一步向左走,因此只需要在做一遍前缀和求出最后一步向上走的方案数就行了。
别忘了因为一开始翻转了坐标系,因此最后要再翻回来。
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+7;
typedef long long LL;
const int mod = 998244353;
LL Pow(LL a,LL b)
{
LL res=1;
while(b)
{
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res;
}
LL G=3,IG=Pow(3,mod-2);
#define Poly vector<LL>
#define len(x) (int)x.size()
#define turn(x,v) x.resize(v)
int tr[N*4];
void Retry(int n)
{
for(int i=0;i<n;i++)
tr[i]=((tr[i>>1]>>1)|((i&1)?(n>>1):0));
}
void NTT(Poly &f,int opt)
{
int n=len(f);
for(int i=0;i<n;i++)
if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int len=2;len<=n;len<<=1)
{
int l=(len>>1);
LL w=Pow(opt==1?G:IG,(mod-1)/len);
for(int i=0;i<n;i+=len)
{
LL g=1;
for(int j=i;j<i+l;j++)
{
LL v=g*f[j+l]%mod;
f[j+l]=(f[j]-v+mod)%mod;
f[j]=(f[j]+v)%mod;
g=1ll*g*w%mod;
}
}
}
}
Poly Mul(Poly f ,Poly g)
{
int n=len(f),m=len(g);
int len=1;
for(;len<=n+m-1;len<<=1);
Retry(len);turn(f,len);turn(g,len);
NTT(f,1);NTT(g,1);
for(int i=0;i<len;i++)
f[i]=1ll*f[i]*g[i]%mod;
NTT(f,-1);
LL invn=Pow(len,mod-2);
for(int i=0;i<len;i++)
f[i]=1ll*f[i]*invn%mod;
turn(f,n);
return f;
}
int n;
LL fac[N],ifac[N];
void init(int x)
{
fac[0]=1;
for(int i=1;i<=x;i++)
fac[i]=1ll*fac[i-1]*i%mod;
ifac[x]=Pow(fac[x],mod-2);
for(int i=x-1;i>=0;i--)
ifac[i]=(LL)ifac[i+1]*(i+1)%mod;
}
LL C(int a,int b)
{
if(a<0||b<0||a<b) return 0;
return (LL)fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}
int a[N],b[N];
vector<int> s[N];
LL pw(int x)
{
if(x&1) return mod-1;
return 1;
}
int main()
{
freopen("easysum.in","r",stdin);
freopen("easysum.out","w",stdout);
cin>>n;
int mx=0;
for(int i=1;i<=n;i++)
scanf("%d %d",&a[i],&b[i]),mx=max(mx,a[i]),b[i]=n-1-b[i];
init(2*n);
mx=max(mx,1);
int B=sqrt(mx*log2(mx));
B=max(B,1);
int cnt=mx/B;
for(int i=1;i<=n;i++)
s[(a[i]/B)].push_back(i);
Poly F;
turn(F,n);
for(int k=cnt;k>=0;k--)
{
for(auto x:s[k])
{
int l=a[x]%B;
for(int i=0;i<=B-l;i++)
if(b[x]+i<n) F[b[x]+i]=(F[b[x]+i]+(LL)pw(i)*C(B-l,i)%mod)%mod;
}
Poly G;
turn(G,n);
for(int i=0;i<n;i++)
G[i]=C(B+i-1,i);
F=Mul(F,G);
}
for(int i=1;i<n;i++)
F[i]=(F[i-1]+F[i])%mod;
reverse(F.begin(),F.end());
for(int i=0;i<n;i++)
printf("%lld ",F[i]);
return 0;
}

本文介绍了一种使用组合数学和生成函数解决路径计数问题的方法。通过坐标系翻转和分块思想,利用多项式卷积进行高效计算,最终得出所有点到指定位置的路径数量总和。
1386

被折叠的 条评论
为什么被折叠?



