zoukankan      html  css  js  c++  java
  • CF1326F2 Wise Men (Hard Version)

    直接算不好算,考虑先算出超集和的答案,最后高维后缀差分求出原本的答案。

    发现超集和的意义下的答案满足:将 (01) 串的连边关系构成图后,会得到若干条链,若两个 (01) 串得到的链长的可重集相同,则这两个 (01) 串的答案相等。因为答案是由全排列贡献的,所以有这个性质。

    考虑直接枚举链长的可重集,也就是直接枚举 (n) 的整数拆分,(18) 的整数拆分只有 (P(18)=385),可以接受。可以通过 (DP) 求出 (g_{i,S}) 表示长度为 (i) 的链,链中的点为 (S) 的方案数。(dfs) 过程中用枚举到对应的链长后进行子集卷积即可,因为最后只用取全集的答案,所以这里可以用集合并卷积来代替子集卷积。

    总复杂度为 (O((n^2+P(n))2^n))

    #include<bits/stdc++.h>
    #define maxn 20
    #define maxm 262154
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,all;
    int cnt[maxm];
    ll f[maxm],g[maxn][maxm],h[maxn][maxm],v[maxn][maxm];
    char w[maxn][maxn];
    vector<int> ve;
    map<vector<int>,ll> mp;
    void dfs(int x,int pre,int sum)
    {
    	if(sum==n)
    	{
    		ll val=0;
    		for(int i=0;i<all;++i) val+=v[x][i]*(cnt[i^(all-1)]&1?-1:1);
    		mp[ve]=val;
    		return;
    	}
    	for(int i=pre;i+sum<=n;++i)
    	{
    		for(int j=0;j<all;++j) v[x+1][j]=v[x][j]*g[i][j];
    		ve.push_back(i),dfs(x+1,i,i+sum),ve.pop_back();
    	}
    }
    int main()
    {
    	read(n),all=1<<n;
    	for(int i=1;i<all;++i) cnt[i]=cnt[i>>1]+(i&1);
    	for(int i=0;i<n;++i) scanf("%s",w[i]),h[i][1<<i]=1;
    	for(int i=0;i<all;++i)
    		for(int j=0;j<n;++j)
    			for(int k=0;k<n;++k)
    				if(!((i>>k)&1)&&w[j][k]=='1')
    					h[k][i|(1<<k)]+=h[j][i];
    	for(int i=0;i<all;++i)
    		for(int j=0;j<n;++j)
    			g[cnt[i]][i]+=h[j][i];
    	for(int x=1;x<=n;++x)
    		for(int len=1;len<all;len<<=1)
    			for(int i=0;i<all;i+=len<<1)
    				for(int j=i;j<i+len;++j)
    					g[x][j+len]+=g[x][j];
    	for(int i=0;i<all;++i) v[0][i]=1;
    	dfs(0,1,0),all>>=1;
    	for(int s=0;s<all;++s)
    	{
    		ve.clear();
    		int pos;
    		for(int i=0;i<n;i=pos+1)
    		{
    			pos=i;
    			while(pos<n-1&&(s>>pos)&1) pos++;
    			ve.push_back(pos-i+1);
    		}
    		sort(ve.begin(),ve.end()),f[s]=mp[ve];
    	}
    	for(int len=1;len<all;len<<=1)
    		for(int i=0;i<all;i+=len<<1)
    			for(int j=i;j<i+len;++j)
    				f[j]-=f[j+len];
    	for(int i=0;i<all;++i) printf("%lld ",f[i]);
        return 0;
    }
    
  • 相关阅读:
    jQuery validator plugin之Selector
    jQuery validator plugin之Methods
    jQuery validator plugin之Plugin Method
    jQuery validator plugin之概要
    jQuery validator plugin 之 custom methods 案例1:multi email
    实体关系图应用——google ads
    Google advertiser api开发概述——入门指南
    Google advertiser api开发概述——部分失败
    Google advertiser api开发概述——批量处理
    oogle advertiser api开发概述——速率限制
  • 原文地址:https://www.cnblogs.com/lhm-/p/14586023.html
Copyright © 2011-2022 走看看