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

    Description

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

    Input

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

    Output

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

    Sample Input

    5 2
    1 3 4 1 2

    Sample Output

    2
     
    正解:$dp$。
    首先可以想到一个很显然的$dp$,$f[i][j][k]$表示前$i$个石子,扔的堆数模$d$为$j$,异或和为$k$的方案数,答案就是$f[n][0][0]$。注意如果$n$是$d$的倍数,那么答案要减一。
    那么$f[i][j][k]=f[i-1][j][k]+f[i][j-1][k^a[i]]$,式子还是比较显然的。
    考虑如何优化,因为题目给了一个条件:$mleq 10000000$,那么我们可以按照石子数来排序,每次$dp$只枚举到当前石子的次数界,这样复杂度就是$O(n+md)$了。
    这题还卡空间,但是我们可以不用滚动,因为$k$和$k^a[i]$是两个互补的转移,直接存一下中间值就行了。
     
     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define rhl (1000000007)
     6 #define S (1048576)
     7 
     8 using namespace std;
     9 
    10 int f[10][S],g[S],a[S],m,n,d;
    11 
    12 il int gi(){
    13   RG int x=0,q=1; RG char ch=getchar();
    14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    15   if (ch=='-') q=-1,ch=getchar();
    16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    17   return q*x;
    18 }
    19 
    20 il int add(RG int a,RG int b){
    21   a+=b; if (a>=rhl) a-=rhl; return a;
    22 }
    23 
    24 int main(){
    25 #ifndef ONLINE_JUDGE
    26   freopen("nim.in","r",stdin);
    27   freopen("nim.out","w",stdout);
    28 #endif
    29   n=gi(),d=gi(),f[0][0]=1;
    30   for (RG int i=1,x;i<=n;++i) ++a[x=gi()],m=max(m,x);
    31   for (RG int i=1,bin=1;i<=m;++i){
    32     while (bin<=i) bin<<=1;
    33     while (a[i]--){
    34       for (RG int k=0;k<bin;++k) g[k]=add(f[0][k^i],f[d-1][k]);
    35       for (RG int j=d-1,x;j;--j)
    36     for (RG int k=0;k<bin;++k){
    37       if (k>(k^i)) continue;
    38       x=f[j][k],f[j][k]=add(f[j-1][k],f[j][k^i]);
    39       f[j][k^i]=add(f[j-1][k^i],x);
    40     }
    41       for (RG int k=0;k<bin;++k) f[0][k]=g[k];
    42     }
    43   }
    44   cout<<add(f[0][0],rhl-(n%d==0)); return 0;
    45 }
  • 相关阅读:
    POJ 3660 Cow Contest (floyd求联通关系)
    POJ 3660 Cow Contest (最短路dijkstra)
    POJ 1860 Currency Exchange (bellman-ford判负环)
    POJ 3268 Silver Cow Party (最短路dijkstra)
    POJ 1679 The Unique MST (最小生成树)
    POJ 3026 Borg Maze (最小生成树)
    HDU 4891 The Great Pan (模拟)
    HDU 4950 Monster (水题)
    URAL 2040 Palindromes and Super Abilities 2 (回文自动机)
    URAL 2037 Richness of binary words (回文子串,找规律)
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7668102.html
Copyright © 2011-2022 走看看