SRM 761 div1 Level 3 SpanningSubgraphs 题解

SRM 761 div1 Level 3 SpanningSubgraphs 题解

\(dp_{mask,i}\)表示集合\(mask\)联通,用的总边数为\(i\)的方案数。

转移考虑容斥,枚举和\(lowbit\)不连通的部分。

假设\(cnt_{mask}\)\(mask\)内的边数。

\(dp_{mask,i}={cnt_{mask}\choose i}-\sum_{0\leq j\leq i}\sum_{smask\subset mask} dp_{mask-smask,j}{cnt_{smask}\choose i-j}\)

后面的东西显然是一个卷积,把他写成生成函数的形式。

\(F_{mask}=\sum_{i\geq 0} dp_{mask,i}x^i\)

\(F_{mask}\)的转移为\(F_{mask}=\sum {cht_{mask}\choose i}x^i-\sum_{smask\subset mask} F_{mask-smask}\times (1+x)^{cnt_{smask}}\)

前面的\(\sum {cht_{mask}\choose i}x^i\)显然就是\((1+x)^{cnt_{mask}}\)

所以可以考虑换元,令\(y=x+1\),得到一个关于\(y\)的多项式,然后向右平移\(1\)就可以得到原多项式。

\(F'_{mask}=y^{cnt}-\sum_{smask\subset mask} F_{mask-smask} *y^{cnt_{smask}}\)

也就是多项式左移然后相加。

时间复杂度为\(O(3^nm)\),常数较小可以通过。

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MOD=1e9+7;
const int MAXN=15;
const int MAXM=250;
int cnt[1<<MAXN];
int c[MAXM][MAXM];
int f[1<<MAXN][MAXM];
int ans[MAXM];
int test[MAXM];
int m;
void recover(int mask){
	rep(i,m+1){
		rep(j,i+1){
			ans[j]+=1ll*f[mask][i]*c[i][j]%MOD;
			ans[j]%=MOD;
		}
	}
}
int fa[MAXN];
int root(int x){
	return fa[x]=(fa[x]==x? x:root(fa[x]));
}
class SpanningSubgraphs{
	public:
		vector<int> count(int n, vector <int> a, vector <int> b){
			m=a.size();
			rep(mask,1<<n) rep(j,m) if(((mask>>a[j])&1)&&((mask>>b[j])&1)) cnt[mask]++;
			rb(i,0,m) c[i][0]=1;
			rb(i,1,m) rb(j,1,m) c[i][j]=c[i-1][j-1]+c[i-1][j],c[i][j]%=MOD;
			rep(i,n) f[1<<i][cnt[1<<i]]=1;
			rep(mask,1<<n){
				if(mask&1)
				if(__builtin_popcount(mask)>1){
					f[mask][cnt[mask]]=1;
					int lowbit=1;
					for(int smask=(lowbit^mask)&((lowbit^mask)-1);;smask=(smask-1)&(lowbit^mask)){
						int _=smask|lowbit;
						int ano=cnt[mask^_];
						rep(j,m-ano+1){
							(f[mask][j+ano]+=MOD-f[_][j]);
							if(f[mask][j+ano]>=MOD) f[mask][j+ano]-=MOD;
						}
						if(smask==0) break;
					}
				}
			}
			vector<int> Ans;
			recover((1<<n)-1);
			rb(i,n-1,m) Ans.PB(ans[i]);
			return Ans;
		}
}solver;

posted @ 2021-07-05 09:37  WWW~~~  阅读(85)  评论(0编辑  收藏  举报