题解:
对于一维是否相交用
2
(
m
2
)
2^{\binom{m}{2}}
2(2m)来表示一下。
然后多维直接FMT做并卷积即可,不过对于一维初始化就需要大力删去重复状态来剪枝了。
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
const int N=40, M=40, K=(1<<16)+20;
class Hyperboxes {
private:
int n,m,t,tot,k,C[M],bin[M],vis[M],a[M],p[M];
int f[K],g[K],id[N][N],tp[N][N],l[N],r[N],cnt;
inline int pos(int x,int y) {return (x>>y)&1;}
inline int calc() {
int sta=0;
for(int i=0;i<m;i++)
for(int j=i+1;j<m;j++) {
if(r[i]<l[j] || r[j]<l[i]) continue;
sta|=1<<id[i][j];
} return sta;
}
inline void dfs(int x,int now) {
if(x==2*m) {
for(int i=0;i<2*m;i++)
(a[i]<m ? l[a[i]] : r[a[i]-m])=p[i];
for(int i=0;i<m;i++) if(l[i]==r[i]) return;
for(int i=0;i<m;i++)
for(int j=i+1;j<m;j++)
if(l[i]==l[j] && r[i]>=r[j]) return;
int s=0;
for(int i=0;i<m;i++)
for(int j=i+1;j<m;j++)
if(r[i]>=l[j]) s|=1<<tp[i][j];
g[s]=add(g[s],C[now+1]);
return;
}
for(int i=0;i<m;i++) if(!vis[i]) {
a[x]=i; vis[i]=1;
p[x]=now+1; dfs(x+1,now+1);
if(x && a[x]>a[x-1]) p[x]=now, dfs(x+1,now);
vis[i]=0;
break;
}
for(int i=0;i<m;i++) if(vis[i] && !vis[i+m]) {
a[x]=i+m; vis[i+m]=1;
p[x]=now+1; dfs(x+1,now+1);
if(x && a[x]>a[x-1]) p[x]=now, dfs(x+1,now);
vis[i+m]=0;
}
}
inline void Dfs(int x) {
if(x==t) {
for(int i=0;i<m;i++) if(!vis[i]) return;
for(int sta=0;sta<(1<<(m*(m-1)/2));++sta) if(g[sta]) {
int s=0;
for(int i=0;i<t;i++)
for(int j=i+1;j<t;j++)
if(p[i]==p[j] || (sta&(1<<tp[p[i]][p[j]]))) s|=(1<<id[i][j]);
f[s]=add(f[s],g[sta]);
}
return;
}
for(int j=0;j<m;j++) {
p[x]=j; ++vis[j];
Dfs(x+1); --vis[j];
}
}
inline int solve() {
C[0]=1;
for(int i=1;i<=2*m;i++) C[i]=mul(C[i-1],n-i+1), C[i]=mul(C[i],power(i,mod-2));
for(int i=0;i<=30;i++) bin[i]=1<<i;
for(int i=0;i<m;i++)
for(int j=i+1;j<m;j++)
id[i][j]=id[j][i]=tot++;
t=m;
for(int i=1;i<=t;i++) {
m=i; int z=0;
memset(g,0,sizeof(g));
for(int j=0;j<m;j++)
for(int k=j+1;k<m;k++)
tp[j][k]=tp[k][j]=z++;
dfs(0,-1);
Dfs(0);
}
dfs(0,-1);
for(int i=1;i<bin[tot];i<<=1)
for(int j=0;j<bin[tot];j++)
if(j&i) f[j^i]=add(f[j^i],f[j]);
for(int j=0;j<bin[tot];j++) f[j]=power(f[j],k);
for(int i=1;i<bin[tot];i<<=1)
for(int j=0;j<bin[tot];j++)
if(j&i) f[j^i]=dec(f[j^i],f[j]);
return f[0];
}
public:
int findCount(int nn, int mm, int kk) {
n=nn; m=mm; k=kk;
return solve();
}
};