• bzoj 4589: Hard Nim


    传送门

    先筛出m以内的质数,g[i]表示i是否是素数

    f[i][j]表示前n堆数异或和为j的方案数。

    f[0][0]=1; f[0][1]~f[0][m]=0;

    f[i][j] = sigma( f[i-1][k] * g[k^j] )

    发现这个玩意满足乘法结合律

    ∴ f[n][] = sigma(f[0][]*g[]*g[]*g[]*g[]……)

      =sigma(f[0]*g[]^n) ;

    f[0][]为单位元

    所以ans=g[]^n

    g[]^n可以用FWT+快速幂来算,时间复杂度就是log^2的

    然后发现每次FWT变换,相乘,答案变回来,再乘的时候再FWT变换,变回来。。这些步骤是不必要的。

    直接FWT然后快速幂,再变换回去就好看,时间复杂度为一个log

    (以上感谢llj同学。)

    然后就是一个愉快的FWT模板

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<ctime>
    const int N=100007,M=50000,mod=1e9+7;
    typedef long long LL;
    using namespace std;
    int n,m,l,bo[M+5],p[M+5];
    LL g[N],inv;
    
    template<typename T> void read(T &x) {
        T f=1; x=0; char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    void get_prime() {
        for(int i=2;i<=M;i++) {
            if(!bo[i]) p[++p[0]]=i;
            for(int j=1;j<=p[0]&&p[j]*i<=M;j++) {
                bo[p[j]*i]=1;
                if(i%p[j]==0) break;
            }
        }
    }
    
    LL ksm(LL a,LL b) {
        LL base=a,res=1;
        while(b) {
            if(b&1) res=res*base%mod;
            base=base*base%mod;
            b>>=1;
        }
        return res;
    }
    
    void FWT(LL a[],int f) {
        for(int i=1;i<n;i<<=1) 
            for(int q=i<<1,j=0;j<n;j+=q) 
                for(int k=0;k<i;k++) {
                    LL x=a[j+k],y=a[j+k+i];
                     if(f==1) {
                         a[j+k]=(x+y)%mod; a[j+k+i]=(x-y+mod)%mod;//^ 
                         //& a[j+k]=x+y;
                         //| a[j+k+i]=x+y;
                     }
                     else {
                         a[j+k]=(x+y)%mod*inv%mod; a[j+k+i]=(x-y+mod)%mod*inv%mod;//^
                         //& a[j+k]=x-y;
                         //| a[j+k+i]=y-x;
                     }
                } 
    }
    
    int main() {
        get_prime(); bo[1]=1; bo[0]=1;
        inv=ksm(2,mod-2);
        while(scanf("%d",&n)!=EOF) {
            read(m); int nn=n;
            memset(g,0,sizeof(g));
            for(int i=0;i<=m;i++) g[i]=(bo[i]==0);
            l=0;
            for(n=1;n<=m;n<<=1) l++;
            FWT(g,1);
            for(int i=0;i<n;i++) g[i]=ksm(g[i],nn);
            FWT(g,-1);
            printf("%lld
    ",g[0]);
        }
        return 0;
    }
    /* 
    3 7
    4 13
    */
    View Code
  • 相关阅读:
    Oct 21st-
    ContextLoaderListener 解析
    HTTPS 证书制作及使用
    Spring MVC 源码分析
    思考
    《深入理解java虚拟机》 第七章虚拟机类加载机制
    《深入理解java虚拟机》第六章 类文件结构
    《深入理解java虚拟机》第三章 垃圾收集器与内存分配策略
    《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常
    SSM-1第一章 认识SSM框架和Redis
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8312914.html
Copyright © 2020-2023  润新知