zoukankan      html  css  js  c++  java
  • 解题:POI 2016 Nim z utrudnieniem

    题面

    出现了,神仙题!

    了解一点博弈论的话可以很容易转化题面:问$B$有多少种取(diu)石子的方式使得取后剩余石子异或值为零且取出的石子堆数是$d$的倍数

    首先有个暴力做法:$dp[i][j][k]$表示到第$i$个为止取出来的石子数目模$d$等于$j$且剩下的石子异或和为$k$的方案数,然后就枚举转移啊=。=

    发现时空复杂度好像都不能承受,不过可以尝试分析/优化一下。首先分析一波后发现时间复杂度其实是对的......只是我们需要将石子数从小到大排个序,这样一路异或下来异或到$i$时最大值不超过$2*a[i]$,复杂度是$O(dm)$的

    然后根据POI的传统我们还不能滚动数组,需要卡空间......那就抓个临时数组记录一下算了=。=

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=1050000,K=11,mod=1e9+7;
     6 int sto[N],mem[N],dp[K][N];
     7 int n,d,ans,goal,maxx;
     8 int main ()
     9 {
    10     scanf("%d%d",&n,&d);
    11     for(int i=1;i<=n;i++)
    12         scanf("%d",&sto[i]),goal^=sto[i];
    13     sort(sto+1,sto+n+1),dp[0][0]=1;
    14     for(int i=1;i<=n;i++)
    15     {
    16         while(maxx<=sto[i]) maxx=maxx<<1|1;
    17         for(int j=0;j<=maxx;j++)
    18             mem[j]=(dp[0][j]+dp[d-1][j^sto[i]])%mod;
    19         for(int j=d-1;j;j--)
    20             for(int k=0;k<=maxx;k++)
    21                 dp[j][k]+=dp[j-1][k^sto[i]],dp[j][k]%=mod;
    22         for(int j=0;j<=maxx;j++) dp[0][j]=mem[j];
    23     }
    24     ans=(dp[0][goal]-(n%d==0)+mod)%mod;
    25     printf("%d",ans);
    26     return 0;
    27 }
    View Code
  • 相关阅读:
    lamp
    mysql多实例部署
    mysql进阶
    rsync
    mysql基础
    httpd
    ftp
    高级命令之awk
    NFS
    网络进阶管理
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9862264.html
Copyright © 2011-2022 走看看