hdu5795 多校第六场 a simple nim

http://acm.hdu.edu.cn/showproblem.php?pid=5795

可以进行一堆分三堆操作的nim多堆问题

nim问题说到底也是sg函数的问题,sg函数求的是当前状态所无法到达的最小状态,这个状态本质是由自己编号的,一般情况下根据石子数目编号,但是不可以采用不同的两套标准。对于分三堆,比如3->(1,2)似乎无法进行sg函数编号,实际上两堆的sg等于两堆独立sg的异或,但是又值得注意的是sg函数所能到达的状态的含义是当前局面的子和子子...局面。

所以sg打表我是模仿这个的,注释的地方很关键

int sg[maxn];
int g(int x){
    int mex[1010];
    memset(mex,0,sizeof(mex));
    if(sg[x]!=-1)
        return sg[x];
    for(int i=x-1;i>=0;i--)
        mex[g(i)]=1;  //g(i),因为必须要考虑到后继能够分堆
    for(int i=1;i<=x/2;i++){
        int ans=0;
        ans^=g(i);//g(i),因为必须要考虑到后继能够分堆
        ans^=g(x-i);//g(i),因为必须要考虑到后继能够分堆
        mex[ans]=1;
    }
    for(int i=0;;i++)
        if(!mex[i])
            return sg[x]=i;
}

int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        NEG(sg);
        printf("%d\n",g(n));
    }
    return 0;
}

最终发现sg函数8个一组有规律

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<string>
#include<cctype>
#include<stack>
#include<queue>
#include<set>
#include<sstream>
#include<map>
using namespace std;
#define For(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,k,n) for(int i=n;i>=k;i--)
#define Lson (u<<1)
#define Rson ((u<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define NEG(a) memset(a,-1,sizeof(a));
#define FILL(a) memset(a,0x3f,sizeof(a));
#define INF 0x3f3f3f3f
#define LLINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define printbin(b,a){int tmp=a;string s;do{s+=tmp%2+‘0‘;tmp/=2;}while(tmp);reverse(s.begin(),s.end());cout<<"bin "<<b<<"="<<s<<endl;}
#define printarr(i,a,f,b) {For(i,f,b) printf("%d ",a[i]); printf("\n");}
#define flgprint(flg,a,b) {if(flg) printf("%s\n",a);else printf("%s\n",b);}
#define fp   freopen("in.txt","r",stdin)
#define maxn 2000

int N,M;
void solve(int a,int b)
{
    int f=true;
    while(true)
    {
        if(a>b) swap(a,b);
        if(b%a==0) break;
        if(b-a>a) break;
        b-=a;
        f=!f;
    }
    flgprint(f,"Stan wins","Ollie wins");
}
int main()
{
    while(scanf("%d %d",&N,&M)==2&&!(N==0&&M==0))
    {
        solve(N,M);
    }
    return 0;
}

时间: 2024-10-11 14:34:51

hdu5795 多校第六场 a simple nim的相关文章

多校第六场 HDU 4927 JAVA大数类

题目大意:给定一个长度为n的序列a,每次生成一个新的序列,长度为n-1,新序列b中bi=ai+1?ai,直到序列长度为1.输出最后的数. 思路:这题实在是太晕了,比赛的时候搞了四个小时,从T到WA,唉--对算组合还是不太了解啊,现在对组合算比较什么了-- import java.io.*; import java.math.*; import java.util.*; public class Main { public static void main(String[] args) { Sca

HDU 4923 Room and Moor (多校第六场C题) 单调栈

Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0 or 1. In order to beat him, programmer Moor has to construct another sequence B = {B1, B2,... , BN} of the same length, which satisfies that: Input The inp

2014多校第六场 1005 || HDU 4925 Apple Tree

题目链接 题意 : 给你一块n×m的矩阵,每一个格子可以施肥或者是种苹果,种一颗苹果可以得到一个苹果,但是如果你在一个格子上施了肥,那么所有与该格子相邻(指上下左右)的有苹果树的地方最后得到的苹果是两倍,如果(i,j)有一颗苹果树,(i-1,j)与(i,j+1)施了肥,那么苹果应该是1的两倍2,2的两倍4,最后是4个苹果,问你怎么安排苹果和施肥的格子使最后得到的苹果最多. 思路 : 画了图就可以看出来,苹果和苹果,肥与肥之间不要相邻就好了,所有的苹果之间都有施肥,所有施肥的格子都被苹果隔开了才能

【HDU】4923 Room and Moor(2014多校第六场1003)

Room and Moor Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 263    Accepted Submission(s): 73 Problem Description PM Room defines a sequence A = {A1, A2,..., AN}, each of which is either 0

2014多校第六场 || HDU 4927 Series 1(杨辉三角组合数)

题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 3 4 5 6 (2-1) (3-2) (4-3) (5-4)(6-5) (3-2-2+1)(4-3-3+2)(5-4-4+3)(6-5-5+4) (4-3-3+2-3+2+2-1)(5-4-4+3-4+3+3-2)(6-5-5+4-5+4+4-3) (5-4-4+3-4+3+3-2-4+3+3-2

2014 HDU多校弟六场J题 【模拟斗地主】

这是一道5Y的题目 有坑的地方我已在代码中注释好了 QAQ Ps:模拟题还是练的太少了,速度不够快诶 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <climits> #include <cstring> #include <cmath> #inclu

2014多校第六场 1010 || HDU 4930 Fighting the Landlords (模拟)

题目链接 题意 : 玩斗地主,出一把,只要你这一把对方要不了或者你出这一把之后手里没牌了就算你赢. 思路 : 一开始看了第一段以为要出很多次,实际上只问了第一次你能不能赢或者能不能把牌出尽. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std ; 6 7 char str1[20],str2[20] ; 8 int hash1[20],hash2[2

多校第六场

01.A boring Question 题意:求题目中给的公式的值,具体见题目. 分析:一开始是不会做的,后来打了一下表,可以观察出规律 a(n+1)=an*m+1.可得到公式(m^(n+1)-1)/(m-1),所以两次快速幂一次求幂一次求逆元就好了,记得取模.有不足的请指正. #include <stdio.h> #define LL long long const int mod=1e9+7; inline LL quick_inverse(LL n, LL p) { LL ret =

2016多校第六场1001-1003(hdu5793&amp;hdu5794&amp;hdu5795)

这场就做出一道题,怎么会有窝这么辣鸡的人呢? 1001 很复杂的公式,打表找的规律,最后是m^0+m^1+...+m^n,题解直接是(m^(n+1)-1)/(m-1),长姿势,原来还能化简……做出来的题不写题解了. 1002 一个棋盘,走棋的姿势要满足(x1-x2)^2+(y1-y2)^2==5,也就是以“日”字走,且只能向右下走. 其中有一些障碍不能经过,注意障碍有可能在终点,求从(1,1)走到(n,m)的路径数. 容斥+组合数 这题的简单版CF559C(对啊,我做过这题,我还是没做出来,wa