• bzoj 4589: Hard Nim


    Description

    Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:

    1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
    2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
      不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
      Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
      由于答案可能很大,你只需要给出答案对10^9+7取模的值。

    Solution

    这是普通的 (nim) 游戏,异或和为 (0) 即先手必败,那么就可以 (DP) 求解了
    (f[i][j]) 表示前 (i) 堆,异或和为 (j) 的方案数
    那么 (f[i][j]=sum f[i-1][p]*f[i-1][q]\,\,p⊕q=j)
    直接 (FWT) 优化一下就好了
    (n) 比较大,用快速幂做一下就行了,注意 (FWT) 要写在快速幂外面,快速幂中做点值运算复杂度才对

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010,mod=1e9+7,inv=500000004;
    int k,n,m;bool vis[N];
    inline void priwork(){
    	for(int i=2;i*i<=50000;i++){
    		if(vis[i])continue;
    		for(int j=i*i;j<=50000;j+=i)vis[j]=1;
    	}vis[0]=vis[1]=1;
    }
    inline void fwt(int *A,int o){
    	for(int i=1;i<n;i<<=1)
    		for(int j=0;j<n;j+=i<<1)
    			for(int k=0;k<i;k++){
    				int x=A[j+k],y=A[j+k+i];
    				if(!o)A[j+k]=(x+y)%mod,A[j+k+i]=(x-y+mod)%mod;
    				else A[j+k]=1ll*(x+y)*inv%mod,A[j+k+i]=1ll*(x-y+mod)*inv%mod;
    			}
    }
    int a[N],b[N];
    inline void work(){
    	for(n=1;n<=m;n<<=1);
    	for(int i=0;i<=m;i++)a[i]=vis[i]^1;
    	b[0]=1;
    	fwt(a,0);fwt(b,0);
    	while(k){
    		if(k&1)for(int i=0;i<=n;i++)b[i]=1ll*b[i]*a[i]%mod;
    		for(int i=0;i<=n;i++)a[i]=1ll*a[i]*a[i]%mod;k>>=1;
    	}
    	fwt(b,1);
    	printf("%d
    ",b[0]);
    	for(int i=0;i<=n;i++)a[i]=b[i]=0;
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      priwork();
      while(~scanf("%d%d",&k,&m))work();
      return 0;
    }
    
    
  • 相关阅读:
    git基本报错处理
    上传本地文件到gitee
    Pycharm Process finished with exit code -1073741819 (0xC0000005)
    linux ubuntu 安装后的配置
    Anaconda 和 jupyter notebook入门
    LaTeX公式小结--持续更新中
    markdown基本语法
    Python数据类型的整理
    linux磁盘分区与挂载
    第一章linux系统概述
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8719142.html
Copyright © 2020-2023  润新知