Topcoder SRM 710 900pts:Hyperboxes(FMT)

题解:
对于一维是否相交用 2 ( m 2 ) 2^{\binom{m}{2}} 来表示一下。

然后多维直接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();
    }
};
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/84022574