zoukankan      html  css  js  c++  java
  • bzoj4589 Hard Nim

    题目描述

    有 $n$ 堆石子,每堆石子是不超过 $m$ 的质数,求有多少种局面,使 $Nim$ 游戏中先手获胜

    数据范围

    $n le 10^9,m le 50000$

    题解

    首先我们知道 $Nim$ 游戏中先手获胜的条件是 $n$ 堆石子异或值为 $0$

    于是我们就 $Fwt$ +快速幂求出第 $0$ 项的值即可

    效率: $O(mlog(nm))$

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1<<17,P=1e9+7,i2=(P+1)>>1;
    int n,m,t,p[N],c,a[N],b[N];bool F[N];
    int X(int x){return x>=P?x-P:x;}
    void Fwt(int *g,int o){
        for (int i=1;i<t;i<<=1)
            for (int j=0;j<t;j+=(i<<1))
                for (int x,y,k=0;k<i;k++){
                    x=g[j+k];y=g[i+j+k];
                    g[j+k]=X(x+y);g[i+j+k]=X(x-y+P);
                    if (!o) g[j+k]=1ll*g[j+k]*i2%P,
                        g[i+j+k]=1ll*g[i+j+k]*i2%P;
                }
    }
    int main(){
        for (int i=2;i<N;i++){
            if (!F[i]) p[++c]=i;
            for (int v,j=1;j<=c;j++){
                v=p[j]*i; if (v>=N) break;
                F[v]=1; if (i%p[j]==0) break;
            }
        }
        while(~scanf("%d%d",&n,&m)){
            for (int j=1;j<=c;j++)
                if (p[j]<=m) a[p[j]]=1;
            for (t=1;t<=m;t<<=1);b[0]=1;
            Fwt(a,1);Fwt(b,1);
            while(n){
                if (n&1)
                    for (int i=0;i<t;i++)
                        b[i]=1ll*b[i]*a[i]%P;
                for (int i=0;i<t;i++)
                    a[i]=1ll*a[i]*a[i]%P;n>>=1;
            }
            Fwt(b,0);printf("%d
    ",b[0]);
            for (int i=0;i<t;i++) a[i]=b[i]=0;
        }
        return 0;
    }
  • 相关阅读:
    011-通过网络协议解析网络请求-DNS-ARP-TCPIP
    010-HTTP协议
    009-DNS域名解析系统
    008-ICMP协议(网络控制文协议)
    007-IP报文协议
    007-排序算法-堆排序
    006-排序算法-希尔排序
    007-Linux 查看端口
    005-排序算法-归并排序
    004-排序算法-选择排序
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/12238847.html
Copyright © 2011-2022 走看看