1. 程式人生 > >洛谷P2575高手過招——SG函數初試

洛谷P2575高手過招——SG函數初試

open isp tdi .org 第一次 mes 結果 aps AR

題目: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\n",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\n"); else printf("NO\n"); } 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\n");
        else printf("NO\n");
    }
    return 0;
}

洛谷P2575高手過招——SG函數初試