【BZOJ】3576: [Hnoi2014]江南乐

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3576



很显然,这是一个multi-nim游戏。

注意:1.一个点的SG值就是一个不等于它的后继点的SG的且大于等于零的最小整数。(mex)

   2.主游戏的SG值等于所有子游戏的异或和

  

   所以区分好主游戏和后继点的区别。

     一开始多个石子堆组合起来形成了一个主游戏。

   一个石子堆可以分为多个石子堆,每一种分发构成了一个主游戏,这些主游戏的异或和构成的当前这个点(状态)的SG函数。

    显然有一个${m^{2}}$做法,即记忆化搜索SG函数。  

考虑${x/i}$只有$\sqrt{n}$种取值,再考虑一下它们的奇偶性,然后分块来做。

70Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 using namespace std;
 9 #define maxn 100100
10 #define llg long long
11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
12 llg n,m,bj[maxn],sg[maxn],T,F,a[maxn];
13
14 llg dp(llg x)
15 {
16     if (bj[x]) return sg[x];
17     bj[x]=1;
18     sg[x]=0;
19     bool e[maxn];
20     memset(e,0,sizeof(e));
21     for (llg m=2;m<=x;m++)
22     {
23         llg v1=m-x%m,v2=x%m;
24         llg nsg=0;
25         if (v1&1) nsg^=dp(x/m);
26         if (v2&1) nsg^=dp(x/m+1);
27         e[nsg]=1;
28     }
29     for (llg i=0;1;i++) if (!e[i]) {sg[x]=i; return sg[x];}
30 }
31
32 int main()
33 {
34     yyj("game");
35     cin>>T>>F;
36     for (llg i=0;i<F;i++) bj[i]=1;
37     while (T--)
38     {
39         scanf("%lld",&n);
40         llg ans=0;
41         for (llg i=1;i<=n;i++)
42         {
43             scanf("%lld",&a[i]);
44             ans^=dp(a[i]);
45         }
46         if (ans) printf("1");else printf("0");
47         if (T) printf(" ");
48     }
49     return 0;
50 }

100Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<cstring>
 8 using namespace std;
 9 #define maxn 100100
10 #define llg int
11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
12 llg n,m,bj[maxn],sg[maxn],T,F,a[maxn];
13
14 llg dp(llg x)
15 {
16     if (bj[x]) return sg[x];
17     bj[x]=1;
18     sg[x]=0;
19     bool e[maxn];
20     memset(e,0,sizeof(e));
21     for (llg m=2,j=0;m<=x;m=j+1)
22     {
23         j=x/(x/m);
24         llg v1=m-x%m,v2=x%m,cnt=j-m+1;
25         llg nsg=0;
26         if (v1&1) nsg^=dp(x/m);
27         if (v2&1) nsg^=dp(x/m+1);
28         e[nsg]=1;
29         if (cnt>=2)
30         {
31             nsg=0;
32             if (((m+1)-x%(m+1))&1) nsg^=dp(x/(m+1));
33                    if ((x%(m+1))&1) nsg^=dp(x/(m+1)+1);
34                    e[nsg]=1;
35         }
36     }
37     for (llg i=0;1;i++) if (!e[i]) {sg[x]=i; return sg[x];}
38 }
39
40 int main()
41 {
42     yyj("game");
43     cin>>T>>F;
44     for (llg i=0;i<F;i++) bj[i]=1;
45     while (T--)
46     {
47         scanf("%d",&n);
48         llg ans=0;
49         for (llg i=1;i<=n;i++)
50         {
51             scanf("%d",&a[i]);
52             ans^=dp(a[i]);
53         }
54         if (ans) printf("1");else printf("0");
55         if (T) printf(" ");
56     }
57     return 0;
58 }
时间: 2024-12-15 03:56:01

【BZOJ】3576: [Hnoi2014]江南乐的相关文章

bzoj 3576: [Hnoi2014]江南乐

Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏. 游戏的规则是这样的,首先给定一个数F,然后游戏系统会产生T组游戏.每一组游戏包含N堆石子,小A和他的对手轮流操作.每次操作时,操作者先选定一个不小于2的正整数M (M是操作者自行选定的,而且每次操作时可不一样),然后将任意一堆数量不小于F的石子分成M堆,并且满足这M堆石子中石子数最多的一堆至多比石子数最少的一堆多1(即分的尽量平均,事

【bzoj3576】 Hnoi2014—江南乐

http://www.lydsy.com/JudgeOnline/problem.php?id=3576 (题目链接) 题意 给出一个数$F$,然后$n$堆石子,每次操作可以把一堆不少于$F$的石子分成$m$堆,$m$是玩家任选的不少于$2$的正整数,这$m$堆石子中最多的一堆与最少的一堆之差不超过$1$,问是否存在先手必胜. Solution 对每一个子游戏考虑如何求解$SG$函数. 假设当前一堆中有$i$石子,我们想把它分成$j$堆,那么石子数为$k=\lfloor{i/j}\rfloor+

bzoj3576[Hnoi2014]江南乐

http://www.lydsy.com/JudgeOnline/problem.php?id=3576 SG函数 我们发现$\left \lfloor \frac{n}{i} \right \rfloor$只有$\sqrt{n}$个取值 不妨设$x=\left \lfloor \frac{n}{i} \right \rfloor$ 那么最终的分割方案一定是下面4种情况之一:偶数个$x$,偶数个$x+1$:偶数个$x$,奇数个$x+1$:奇数个$x$,偶数个$x+1$:奇数个$x$,奇数个$x+

BZOJ 3576 江南乐

http://www.lydsy.com/JudgeOnline/problem.php?id=3576 思路:由于数字巨大,因此N^2异或做法是过不了的,我们考虑将n个石子分成i堆,那么会有n%i堆n/i+1的石子,i-n%i堆n/i的石子.如果两个堆的石子数相同,那么他们异或起来就为0,因此,这两种石子堆,我们可以看做:每种至多只有1堆.这样就可以枚举n/i,然后可以避免计算很多重复的部分,时间复杂度为N^1.5 1 #include<algorithm> 2 #include<cs

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

[BZOJ 3573][Hnoi2014]米特运输(乱搞)

Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都.这N个城市由N-1条单向高速 通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲.树按深度分层: 根结点深度为0,属于第1层:根结点的子节点深度为1,属于第2层:依此类推,深度为i的结点属于第i+l层.建好 高速通道之后,D星人开始考虑如何具体地储存和传输米

bzoj 3575: [Hnoi2014]道路堵塞

Description A 国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所有从城市1到城市N的路径中最短的.不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞. 现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少. Input 输入文件第一行是三个用空格分开的正整数N.M和L,分别表示城市数目.单向道路数目

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

bzoj 3572: [Hnoi2014]世界树

再次跪虚树(DP)(两遍DP挺有意思的..) (这个题的情况,,跪) %%%http://hzwer.com/6804.html 1 #include <bits/stdc++.h> 2 #define LL long long 3 #define N 300005 4 using namespace std; 5 inline int ra() 6 { 7 int x=0,f=1; char ch=getchar(); 8 while (ch<'0' || ch>'9') {if