P10004 [集训队互测 2023] Permutation Counting 2
这也太 hard 了,如何想到这个双射 /wq。
对于 \(P\) 恰好 \(i\) 个上升对,\(P^-\) 恰好 \(j\) 个上升对计数记作 \(f_{i,j}\)。不妨考虑计数 \(P\) 至少 \(i\) 个上升对,\(P^-\) 至少 \(j\) 个上升对 \(g_{i,j}\)。
考虑计算 \(g_{i,j}\)。
神仙。首先有 \(i\) 个上升对意味着有 \(n-1-i\) 个下降对,而每个下降对相当于新开一个上升段。也就是说 \(P\) 至少由 \(n-i\) 个上升段组成。每个上升段中相当于 \(P^-\) 中的 \([l,r]\) 依次分配到 \(p_i,p_{i+1},p_{i+2},\cdots\)。而每个上升段 \([l,r]\) 中 \(p_i\) 递增 \(i\) 也递增,等价于向 \(P^-\) 中填入了一个上升序列。然后将 \(P^-\) 分成至少 \(j\) 个上升段的方案数。这个既跟 \(P\) 中上升段的情况有关,又跟填入的情况有关,计数又困又难。
若固定 \(P^-\) 中的上升段 \([l,r],[l_1,r_1],[l_2,r_2],\cdots\),要满足此条件即为段内排序。对于 \(P\) 相同的情况,这样影响 \(P^-\) 结果的条件就只有每个段内出现的数。
考虑填入第 \(i\) 个上升序列时,向 \(P^-\) 第 \(j\) 个连续段填入了 \(c_{i,j}\) 个数。当所有的 \(c_{i,j}\) 定下来时,记 \(s_{i}\) 为前 \(i\) 个连续段向逆序列填入了多少数,\(P\) 的第 \(i\) 个上升段即为 \((s_{i-1},s_i]\)。而 \(P_i\) 等于 \(P^-\) 每段排好序后 \(i\) 所在的位置。也就是 \(c\) 固定后 \(P\) 与 \(P^-\) 的情况均确定。
则两种方案不同当且仅当存在两种方案 \(c_{i,j}\ne c'_{i,j}\)。
所以现在相当于计数每种 \(i\times j\) 矩阵 \(c\) 的可能情况,要求满足每行、每列的和 \(>0\)(表示 \(P\) 与 \(P^-\) 中的上升段不为空)并且矩阵和 \(=n\)(显然 \(P\) 中所有上升段的大小和为 \(n\)),记作 \(t_{i,j}\)。至于这个双射的证明是容易的。
第一种限制较为严格不好满足,考虑计数 \(i\times j\) 且和 \(=n\) 的矩阵后容斥,记为 \(w_{i,j}\)。
钦定有 \(x\) 行 \(y\) 列和 \(>0\)。
发现又是二项式反演的形式。
而 \(w_{i,j}\) 是容易得到的,\({n+i\cdot j-1\choose i\cdot j-1}\)。
于是两个反演就能做到 \(O(n^4)\) 容斥。还需优化,以 \(t\) 为例:
后一个求和与 \(i\) 无关,于是套路的先计算 \(l_{x,y}=\sum_{y=0}^j{j\choose y}(-1)^{j-y}w_{x,y}\)。
就能够优化至 \(O(n^3)\),\(f\) 同理。
还卡常🔥🔥🔥🔥🔥,容斥的时候 \(-1\) 不要写成 \(mod-1\) 的形式,最后输出答案的时候再考虑负数,不然 \(mod\) 的次数会增加很多。还有组合数可以预处理也能避免多次计算时的 \(mod\)。
UesugiErii
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){
ll x=0,f=1;char ch=nc();
while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}
while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();
return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
int mod=998244353;
ll qp(ll x,int y){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=505;
ll g[N][N],c[N][N],n,f[N][N],ans[N][N],fac[N*N+N],ifac[N*N+N];
inline ll C(int x,int y){return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}
inline ll calc(int x,int y){return C(n+x*y-1,x*y-1);}
inline void UesugiErii(){
cin>>n>>mod;
for(int i=fac[0]=1;i<=n*n+n;++i)fac[i]=fac[i-1]*i%mod;
ifac[n*n+n]=qp(fac[n*n+n],mod-2);
for(int i=n*n+n;i;--i)ifac[i-1]=ifac[i]*i%mod;
for(int i=0;i<=n;++i)
for(int j=c[i][0]=1;j<=i;++j){
c[i][j]=c[i-1][j-1]+c[i-1][j];
if(c[i][j]>=mod)c[i][j]-=mod;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=j;++k)
(g[i][j]+=c[j][k]*((j-k)&1?-1:1)*calc(i,k))%=mod;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
for(int k=1;k<=i;++k)
(f[i][j]+=c[i][k]*((i-k)&1?-1:1)*g[k][j])%=mod;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j){
g[i][j]=0;
for(int k=j;k<n;++k)
(g[i][j]+=c[k][j]*((k-j)&1?-1:1)*f[n-i][n-k])%=mod;
}
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
for(int k=i;k<n;++k)
(ans[i][j]+=c[k][i]*((k-i)&1?-1:1)*g[k][j])%=mod;
for(int i=0;i<n;i++,cout<<'\n')
for(int j=0;j<n;j++)cout<<(ans[i][j]+mod)%mod<<' ';
}
signed main(){
//IO();
cfast;
int _=1;//cin>>_;
for(;_;_--)UesugiErii();
return 0;
}

浙公网安备 33010602011771号