传送门
题解:
两个高维立方图形相交,当且仅当在每一维都相交。
发现对于某个维度的相交情况,每一维是相同的。
所以我们算出一维的情况后FMT即可。
直接算很扯,考虑将所有端点排序,发现我们可以枚举端点的排列顺序。
注意到有的端点可能重合,我们需要枚举哪些端点重合。
也就是,我们需要直接枚举哪些端点是不一样的,分别在哪个组里面,然后对于一个端点的分组和偏序,我们爆搜有多少种划分方式满足它就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using namespace std;
cs int mod=998244353;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
return res;
}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
class Hyperboxes{
private:
static cs int N=15,SIZE=1<<16|1;
int n,m,k,t,tot,S;
int C[N],id[N][N],idg[N][N];
int g[SIZE],f[SIZE];
int a[N],gr[N],l[N],r[N],vis[N];
void pre_dfs(int cur,int gcnt){
if(cur==2*m){
for(int re i=0;i<2*m;++i)
(a[i]<m?l[a[i]]:r[a[i]-m])=gr[i];
for(int re i=0;i<m;++i)if(l[i]==r[i])return ;
for(int re i=0;i<m;++i)
for(int re j=i+1;j<m;++j)
if(l[i]==l[j]&&r[i]>=r[j])return ;
int st=0;
for(int re i=0;i<m;++i)
for(int re j=i+1;j<m;++j)
if(r[i]>=l[j])st|=1<<idg[i][j];
Inc(g[st],C[gcnt+1]);
return ;
}
for(int re i=0;i<m;++i)if(!vis[i]){
a[cur]=i,vis[i]=true;
gr[cur]=gcnt+1;
pre_dfs(cur+1,gcnt+1);
if(cur&&a[cur]>a[cur-1]){
gr[cur]=gcnt;
pre_dfs(cur+1,gcnt);
}
vis[i]=false;
break;
}
for(int re i=0;i<m;++i)if(vis[i]&&!vis[i+m]){
a[cur]=i+m;vis[i+m]=true;
gr[cur]=gcnt+1;
pre_dfs(cur+1,gcnt+1);
if(cur&&a[cur]>a[cur-1]){
gr[cur]=gcnt;
pre_dfs(cur+1,gcnt);
}
vis[i+m]=false;
}
}
inline void dfs(int cur){
if(cur==t){
for(int re i=0;i<m;++i)if(!vis[i])return ;
for(int s=0,S=(1<<(m*(m-1)>>1));s<S;++s)if(g[s]){
int st=0;
for(int re i=0;i<t;++i)
for(int re j=i+1;j<t;++j)
if(gr[i]==gr[j]||(s&(1<<idg[gr[i]][gr[j]])))st|=1<<id[i][j];
Inc(f[st],g[s]);
}
return ;
}
for(int re j=0;j<m;++j){
gr[cur]=j;++vis[j];
dfs(cur+1);--vis[j];
}
}
inline int solve(){
C[0]=1;for(int re i=1;i<=m*2;++i)C[i]=mul(C[i-1],n-i+1),Mul(C[i],power(i,mod-2));
for(int re i=0;i<m;++i)
for(int re j=i+1;j<m;++j)id[i][j]=id[j][i]=tot++;
t=m;
for(m=1;m<=t;++m){
int tp=0;
for(int re i=0;i<m;++i)
for(int re j=i+1;j<m;++j)
idg[i][j]=idg[j][i]=tp++;
memset(g,0,sizeof g);
pre_dfs(0,-1);
dfs(0);
}S=1<<tot;
for(int re i=1;i<S;i<<=1)
for(int re j=0;j<S;j+=i<<1)
for(int re k=0;k<i;++k)Inc(f[j+k],f[i+j+k]);
for(int re i=0;i<S;++i)f[i]=power(f[i],k);
for(int re i=1;i<S;i<<=1)
for(int re j=0;j<S;j+=i<<1)
for(int re k=0;k<i;++k)Dec(f[j+k],f[i+j+k]);
return f[0];
}
public:
Hyperboxes(){}
int findCount(int _n,int _m,int _k){
n=_n,m=_m,k=_k;return solve();
}
};
#ifdef zxyoi
using namespace std;
Hyperboxes Solver;
signed main(){
cerr<<Solver.findCount(1000,3,1)<<"\n";
return 0;
}
#endif