• 洛谷P2575高手过招——SG函数初试


    题目:https://www.luogu.org/problemnew/show/P2575

    第一次用SG函数解决问题,有许多不熟练的地方;

    试图按自己的理解写一个dfs,结果错了(连题都没读对,以为是像跳棋一样跳),这样的话用dfs从左往右推就不行了呢;

    附上自己的错误尝试:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int maxn=200005;
    int T,n,p,ans,g[2100000];
    int dfs(int x)
    {
        if(g[x])return g[x]-1;
        int ret=0;
        for(int i=20;i>=1;i--)
            if(x&(1<<i))
            {
                if((x&(1<<(i-1)))&&(x&(1<<(i-2)))==0&&i-2>=0)
                {
                    int k=x-(1<<i)+(1<<(i-2));
    //                if(!dfs(k))
    //                {
    //                    g[x]=2;
    //                    return 1;
    //                }
                    ret^=dfs(k);
                }
                if((x&(1<<(i-1)))==0&&i-1>=0)
                {
                    int k=x-(1<<i)+(1<<(i-1));
    //                if(!dfs(k))
    //                {
    //                    g[x]=2;
    //                    return 1;
    //                }
                    ret^=dfs(k);
                }
            }
        
        if(!ret)g[x]=1;
        else g[x]=2;
    //    printf("%d %d
    ",x,g[x]-1);
        return g[x]-1;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            memset(g,0,sizeof g);
            ans=0;
            scanf("%d",&n);
            for(int i=1,m;i<=n;i++)
            {
                p=0;
                scanf("%d",&m);
                for(int j=1,x;j<=m;j++)
                {
                    scanf("%d",&x);
                    x--;
                    p|=(1<<(20-x));
                }
    //            if(ans)continue;
    //            if(dfs(p)==0)ans=1;
                ans^=dfs(p);
            }
            if(ans)printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }

    下面是正解,也就是个SG函数的模板;

    状压一下每一行,先预处理出来所有状态的SG函数值(注意vis[里面是SG函数值]),然后每次询问异或一下就可以了,还挺简明的。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int T,n,m,ans,sg[1<<20];
    bool vis[25];
    void init(int x)
    {
        memset(vis,0,sizeof vis);
        int w=0;
        for(int i=1;i<=20;i++)//从小到大对应从右往左
        {
            int t=(1<<(i-1));
            if(x&t)
            {
                if(i>1&&(x&(t>>1))==0)
                    vis[sg[x-t+(t>>1)]]=1;
    //            if(i>2&&(x&(t>>1))&&(x&(t>>2))==0)
    //                vis[sg[x-t+(t>>2)]]=1;//读错题 
                if((x&(t>>1))&&w)
                    vis[sg[x-t+(1<<(w-1))]]=1;
            }
            else w=i;
        }
        int k=0;//求mex 
        while(vis[k])k++;
        sg[x]=k;
    }
    int main()
    {
        scanf("%d",&T);
        for(int i=0;i<=(1<<20)-1;i++)init(i);
        while(T--)
        {
            ans=0;//!
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&m);
                int p=0;
                for(int j=1,x;j<=m;j++)
                {
                    scanf("%d",&x);
                    p|=(1<<(20-x));
                }
                ans^=sg[p];
            }
            if(ans)printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
  • 相关阅读:
    锋利的jQuery复制粘贴(一)
    使用photoshop以及markman进行快速重构页面的几个步骤
    线程间同步之 semaphore(信号量)
    关于C#中Thread.Join()的一点理解
    无废话WCF入门教程一[什么是WCF]
    Oracle function注释
    throw new DataException("检查服务器是否存在失败:" + ex);
    C# 将数据集以excel的形式输出
    .net 安装remoting服务
    任务计划 每日删除设定目录内的文件(包括文件夹)
  • 原文地址:https://www.cnblogs.com/Zinn/p/9080542.html
Copyright © 2020-2023  润新知