zoukankan      html  css  js  c++  java
  • 【bzoj4347】[POI2016]Nim z utrudnieniem dp

    题目描述

    A和B两个人玩游戏,一共有m颗石子,A把它们分成了n堆,每堆石子数分别为a[1],a[2],...,a[n],每轮可以选择一堆石子,取掉任意颗石子,但不能不取。谁先不能操作,谁就输了。在游戏开始前,B可以扔掉若干堆石子,但是必须保证扔掉的堆数是d的倍数,且不能扔掉所有石子。A先手,请问B有多少种扔的方式,使得B能够获胜。

    输入

    第一行包含两个正整数n,d(1<=n<=500000,1<=d<=10)。
    第二行包含n个正整数a[1],a[2],...,a[n](1<=a[i]<=1000000)。
    本题中m不直接给出,但是保证m<=10000000。

    输出

    输出一行一个整数,即方案数对10^9+7取模的结果。

    样例输入

    5 2
    1 3 4 1 2

    样例输出

    2


    题解

    dp

    Nim游戏后手必胜条件:每堆的异或和为0

    拿到这道题很容易想到是一道动态规划,并且能够想到状态f[i][j][k]表示前i个数中选出的数的个数mod d=j,使得异或和为k的方案数,初始化f[0][0]=1。

    然而这样时间复杂度为$O(nmd)$,显然TLE。

    我们可以考虑:如果将所有数从小到大排序,那么每次新加入一个数,数的上界的最高位一定不会大于当前数的最高位,一定不会大于2*a[i]。

    所以这样可以把时间复杂度压到$O(sumlimits_{i=1}^na_id)=O(md)$。

    至于空间的问题,很容易想到使用滚动数组优化,然而还是会MLE。

    其实并不需要滚动数组,由于k>0时用到的状态都是k-1,所以可以按照01背包的思路倒过来枚举k。当k=0时不成立,所以还要再开一个数组记录一下f[][d-1]的值.

    常数较大。。。但有一个重要的点:二维数组一定要把较小的模数维放到第一维!

    亲测把异或维放到第一维时间28s,把模数维放到第一维11s,大概是内部的内存分配问题。

    最后的答案是f[0][sum],其中sum为所有数的异或和;另外由于不能拿走所有数,所以需要判断一下n%d是否为0并对应地减1。

    #include <cstdio>
    #include <algorithm>
    #define N 500010
    #define M (1 << 20) + 10
    using namespace std;
    const int mod = 1000000007;
    int a[N] , f[10][M] , t[M];
    int main()
    {
    	int n , d , i , j , k , sum = 0 , m = 1;
    	scanf("%d%d" , &n , &d);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , sum ^= a[i];
    	sort(a + 1 , a + n + 1);
    	f[0][0] = 1;
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		while(m <= a[i]) m <<= 1;
    		for(j = 0 ; j < m ; j ++ ) t[j] = f[d - 1][j];
    		for(k = d - 1 ; k ; k -- )
    			for(j = 0 ; j < m ; j ++ )
    				f[k][j] = (f[k][j] + f[k - 1][j ^ a[i]]) % mod;
    		for(j = 0 ; j < m ; j ++ ) f[0][j] = (f[0][j] + t[j ^ a[i]]) % mod;
    	}
    	printf("%d
    " , (f[0][sum] - (n % d == 0) + mod) % mod);
    	return 0;
    }
    

     

  • 相关阅读:
    quick-cocos2d-x + Lua 开发
    设置 Quick-Cocos2d-x 在 Windows 下的编译环境
    luaIDE选择
    接管radiobutton onclick 事件
    AlphaControls的使用方法
    Delphi程序调用C#.Net编译的DLL并打开窗体(详解)
    delphi 正则表达式
    Windows server 2003 伪静态配置方法
    windows 2003 iis php
    Linux Shell系列教程之(十一)Shell while循环
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7055243.html
Copyright © 2011-2022 走看看