P10004题解
前言:
这是蒟蒻做的第一道二项式反演,一开始反演的方向反了(致敬反方向的钟
科技:
二项式反演
思路:
直接计算
剩下的事就是求
我们钦定了原排列、逆排列中各有
设
设
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 510,M = 250510;
int n,v,mod,inv[M],fac[M],ifac[M],ans[N][N],g[N][N],t[N][N],s[N][N],c[N][N];
int C(int n,int m){return 1LL * fac[n] * ifac[m] % mod * ifac[n - m] % mod;}
int main()
{
scanf("%d%d",&n,&mod);
v = n * n + n;
inv[1] = fac[0] = ifac[0] = 1;
for(int i = 2;i <= v;i++) inv[i] = mod - 1LL * (mod / i) * inv[mod % i] % mod;
for(int i = 1;i <= v;i++)
{
fac[i] = 1LL * fac[i - 1] * i % mod;
ifac[i] = 1LL * ifac[i - 1] * inv[i] % mod;
}
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
t[i][j] = C(n + i * j - 1,i * j - 1);
for(int i = 0;i <= n;i++)
{
c[i][0] = 1;
for(int j = 1;j <= i;j++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
int tmp;
for(int j = 1;j <= n;j++)
for(int a = 1;a <= n;a++)
for(int b = 1;b <= j;b++)
{
tmp = 1LL * c[j][b] * t[a][b] % mod;
if((j - b) & 1) s[j][a] = (s[j][a] - tmp + mod) % mod;
else s[j][a] = (s[j][a] + tmp) % mod;
}
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
for(int a = 1;a <= i;a++)
{
tmp = 1LL * c[i][a] * s[j][a] % mod;
if((i - a) & 1) g[i][j] = (g[i][j] - tmp + mod) % mod;
else g[i][j] = (g[i][j] + tmp) % mod;
}
memset(s,0,sizeof(s));
for(int j = 0;j < n;j++)
for(int a = 0;a < n;a++)
for(int b = j;b < n;b++)
{
tmp = 1LL * c[b][j] * g[n - a][n - b] % mod;
if((b - j) & 1) s[j][a] = (s[j][a] - tmp + mod) % mod;
else s[j][a] = (s[j][a] + tmp) % mod;
}
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
for(int a = i;a < n;a++)
{
tmp = 1LL * c[a][i] * s[j][a] % mod;
if((a - i) & 1) ans[i][j] = (ans[i][j] - tmp + mod) % mod;
else ans[i][j] = (ans[i][j] + tmp) % mod;
}
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++) printf("%d ",ans[i][j]);
puts("");
}
return 0;
}