zoukankan      html  css  js  c++  java
  • uoj310【UNR #2】黎明前的巧克力(FWT)

    uoj310【UNR #2】黎明前的巧克力(FWT)

    uoj

    题解时间

    对非零项极少的FWT的优化。

    首先有个十分好想的DP: $ f[i][j] $ 表示考虑了前 $ i $ 个且异或和为 $ j $ 的方案数,

    有 $ f[i][j]= f[i-1][j] + 2 * f[i-1][j oplus a[i]] $ 。

    可以考虑FWT,但很明显时间复杂度没有优化。

    但另一方面,每层的卷积卷的都是 $ 1,0,0,...,2,0,0,... $ 的形式,

    这样一来卷之后每项都是 $ -1 $ 或 $ 3 $ 。

    因此大胆一点直接把所有的式子加到一起卷积,

    卷完有什么用呢?

    这样卷出来的结果是每层卷积相加,而正常FWT求解是每层卷积相乘。

    每一位都是共计 $ n $ 个 $ -1 $ 和 $ 3 $ 加一起,所以可以求出每一位上两种数的个数。

    由于知道了每一位上两种数的个数,直接每一位快速幂就能求出原来的相乘结果。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long lint;
    struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
    template<typename TP>inline void read(TP &tar)
    {
    	TP ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
    	tar=ret*f;
    }
    template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
    namespace RKK
    {
    const int N=2000011;
    const int defaultlen=1048576;
    const int mo=998244353,inv2=499122177,inv4=748683265;
    void doadd(int &a,int b){if((a+=b)>=mo) a-=mo;}int add(int a,int b){return (a+=b)>=mo?a-mo:a;}
    void domul(int &a,int b){a=1ll*a*b%mo;}int mul(int a,int b){return 1ll*a*b%mo;}
    int fpow(int a,int p){int ret=1;while(p){if(p&1) domul(ret,a);domul(a,a),p>>=1;}return ret;}
    int n,a[N];
    void fwtxor(int *a,int len,int tp)
    {
    	for(int i=1,w1,w2;i<len;i<<=1)
    	for(int j=0;j<len;j+=i<<1)
    	for(int k=0;k<i;k++)
    	{
    		w1=a[j+k],w2=a[j+k+i];
    		a[j+k]=add(w1,w2),a[j+k+i]=add(w1,mo-w2);
    		if(tp==-1) domul(a[j+k],inv2),domul(a[j+k+i],inv2);
    	}
    }
    int main()
    {
    	read(n);for(int i=1,w;i<=n;i++) read(w),a[0]+=1,a[w]+=2;
    	fwtxor(a,defaultlen,1);
    	for(int i=0,cnt1,cnt3;i<defaultlen;i++)
    	{
    		cnt3=mul(add(n,a[i]),inv4),cnt1=n-cnt3;
    		a[i]=(cnt1&1)?mo-fpow(3,cnt3):fpow(3,cnt3);
    	}
    	fwtxor(a,defaultlen,-1);
    	printf("%d
    ",add(a[0],mo-1));
    	return 0;
    }
    }
    int main(){return RKK::main();}
    
  • 相关阅读:
    aspnetpager 详解
    删除sql数据库日志的方法
    Asp.Net 自带的分布式事务(TransactionScope)的代码块
    VS2010项目放到VS2008下的方法
    SQL Server 2005中的SSIS维护计划
    XML格式与DataTable、DataSet、DataView格式的转换
    .NET公共执行类
    C#学习BackgroundWork
    <winform>源代码
    C#学习Thread
  • 原文地址:https://www.cnblogs.com/rikurika/p/13370358.html
Copyright © 2011-2022 走看看