C-Cells
题意:给定n个点(0,
a
1
a_1
a1),(0,
a
2
a_2
a2),(0,
a
3
a_3
a3)…(0,
a
n
a_n
an)求他们各自分别到对应点(1,0),(2,0),(3,0)…(n,0)的不相交路径的所有合法方案数。
题解:首先要学习LGV引理。集合A上的点到集合B上的点所有不相交路径的方案数等于
题目所求就为求行列式
展开
对于第j列都有
1
j
!
\frac{1}{j!}
j!1可以提出来,接着消元,以第一行为例子
不难发现答案为范德蒙行列式,但需要提出
a
i
+
1
a_i+1
ai+1,所以答案为
∏
i
=
1
n
1
i
!
\prod_{i=1}^{n}{\frac{1}{i!}}
∏i=1ni!1
∏
i
=
1
n
a
i
+
1
\prod_{i=1}^{n}{a_i+1}
∏i=1nai+1
∏
1
<
=
j
<
i
<
=
n
a
i
−
a
j
\prod_{1<=j<i<=n}{a_i-a_j}
∏1<=j<i<=nai−aj,后面那部分计算两数之差的乘积可以使用fft。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,bit,tot;
const double PI=acos(-1);
const int N=6e6+10;
const int mod=998244353;
const int M=1e6;
int num[N],rev[N];
ll ppow(ll x,int i)
{
ll ans=1,res=x;
while(i)
{
if(i&1)ans=(ans*res)%mod;
res=(res*res)%mod;
i>>=1;
}
return ans;
}
struct Complex
{
double x,y;
Complex operator +(const Complex &t)const
{
return {x+t.x,y+t.y};
}
Complex operator -(const Complex &t)const
{
return {x-t.x,y-t.y};
}
Complex operator *(const Complex &t)const
{
return {x*t.x-y*t.y,x*t.y+y*t.x};
}
}a[N],b[N];
void init()
{
while((1<<bit)<2000010)bit++;
tot=1<<bit;
for(int i=0;i<tot;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
return;
}
void fft(Complex a[],int inv)
{
for(int i=0;i<tot;i++)
{
if(i<rev[i])swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<tot;mid<<=1)
{
Complex wk={cos(PI/mid),inv*(sin(PI/mid))};
for(int i=0;i<tot;i+=2*mid)
{
Complex w1={1,0};
for(int j=0;j<mid;j++,w1=w1*wk)
{
Complex x=a[i+j],y=w1*a[i+j+mid];
a[i+j]=x+y;
a[i+j+mid]=x-y;
}
}
}
return;
}
int main ()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&num[i]);
ll ans=1,res=1;
for(int i=1;i<=n;i++)
{
res=res*ppow(i,mod-2)%mod;
ans=(ans*res)%mod;
}
for(int i=1;i<=n;i++)
{
ans=(ans*(num[i]+1))%mod;
}
for(int i=1;i<=n;i++)
{
a[num[i]].x=1;
b[M-num[i]].x=1;
}
init();
fft(a,1);
fft(b,1);
for(int i=0;i<tot;i++)a[i]=a[i]*b[i];
fft(a,-1);
for(int i=M+1;i<tot;i++)
{
int x=a[i].x/tot+0.5;
if(x)ans=ans*ppow(i-M,x)%mod;
}
cout<<ans<<endl;
return 0;
}