• 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;
    }
    
  • 相关阅读:
    仰视源代码,实现strcmp
    Wicket实战(一)概述
    在弱网传输的情况下,是怎么做到节约流量的(面试小问题,Android篇)
    nRF52832之硬件I2C
    Android开源项目SlidingMenu的学习笔记(一)
    MVC设计模式
    报表应用结构优化之数据分库存储
    extern &quot;C&quot; 的含义:实现C++与C及其他语言的混合编程
    phpstorm改变文件编码由utf变为gbk
    mysql database 格式的查看和改变
  • 原文地址:https://www.cnblogs.com/lhm-/p/14586023.html
Copyright © 2020-2023  润新知