zoukankan      html  css  js  c++  java
  • luogu P6097 子集卷积 FST FWT

    LINK:子集卷积

    学了1h多 终于看懂是怎么回事了(题解写的不太清楚 翻了好几篇博客才懂

    一个需要用到的性质 二进制位为1个数是i的二进制数s 任意两个没有子集关系。挺显然。

    而FST就是利用这个性质靠FWT做的。

    直接说做法:

    定义(f_{i,s})表示|s|为i状态为s的值.

    对于另一个g数组也同时定义。设答案为h.

    那么有 (h_{i,s}=sum_{j subseteq s}f_{|j|,j}cdot sum_{wsubseteq s,w|j==s}g_{i-|j|,w})

    暴力做这个还是(3^n) 但是可以发现此时限制松动了对于第二个状态我们不再要求交集为空了 但是如果交集不为空在第一个限制下.

    就会出现依然合法的情况. 所以只需要对(f_j,g_{i-j})进行或卷积即可.

    const int MAXN=300010,GG=3;
    int n,maxx;
    int sum[1<<20];
    int a[22][1<<20],b[22][1<<20],f[22][1<<20];
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline int mux(int x,int y){return x-y<0?x-y+mod:x-y;}
    inline void FWT(int *a)
    {
    	for(int len=2;len<=maxx+1;len=len<<1)
    	{
    		int mid=len>>1;
    		for(int j=0;j<=maxx;j+=len)
    		{
    			for(int i=0;i<mid;++i)
    			{
    				a[i+j+mid]=add(a[i+j+mid],a[i+j]);
    			}
    		}
    	}
    }
    inline void IFWT(int *a)
    {
    	for(int len=2;len<=maxx+1;len=len<<1)
    	{
    		int mid=len>>1;
    		for(int j=0;j<=maxx;j+=len)
    		{
    			for(int i=0;i<mid;++i)
    			{
    				a[i+j+mid]=mux(a[i+j+mid],a[i+j]);
    			}
    		}
    	}
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(n);maxx=1<<n;--maxx;
    	rep(0,maxx,i)sum[i]=sum[i>>1]+(i&1),get(a[sum[i]][i]);
    	rep(0,maxx,i)get(b[sum[i]][i]);
    	rep(0,n,i)FWT(a[i]),FWT(b[i]);
    	rep(0,n,i)
    	{
    		rep(0,maxx,s)rep(0,i,j)f[i][s]=add(f[i][s],(ll)a[j][s]*b[i-j][s]%mod);
    		IFWT(f[i]);
    	}
    	rep(0,maxx,i)put_(f[sum[i]][i]);return 0;
    }
    
  • 相关阅读:
    .net持续集成cake篇之使用vs或者vscode来辅助开发cake脚本
    Redis集合类型
    Git如何合并Commit
    Redis列表类型
    Redis散列表类型
    Redis字符串类型
    2. 引用计数法(Reference Counting)
    调皮的控制台
    Python str与bytes之间的转换
    安全速查
  • 原文地址:https://www.cnblogs.com/chdy/p/13027596.html
Copyright © 2011-2022 走看看