zoukankan      html  css  js  c++  java
  • Luogu P3727 曼哈顿计划E 点分治+hash

    题目:

      P3727曼哈顿计划E

    分析:

      大长题面容易给人一种不可做的错觉,但是这题考的知识点都是我们熟悉的。

      稍加分析我们可以得到,我们可以把每个点当成一个单独的游戏,如果k=1,就是简单的nim游戏,这样,当多个游戏放在一起的时候,我们就可以根据一条链的权值异或和来判断必胜必败。

      这个给我们启发,根据SG定理(应该是这个定理?)当我们选一条链,根据这条链上所有点的SG函数的异或和,可以判断胜负。

      所以我们可以对于每个k想办法求点的sg函数,就可以用点分治解决这个题。

      怎么求sg函数?(打表找规律啊),或者如果你有办法推也可以。

     代码:

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a))
     3 using namespace std;
     4 const int N=30005,M=1e7;
     5 struct node{int y,nxt;}e[N*2];
     6 int t,n,k,s,c=0,hs,pd,nt,h[N];
     7 int w[N],siz[N],vis[N],tp[N],tt[N];
     8 void add(int x,int y){
     9     e[++c]=(node){y,h[x]};h[x]=c;
    10     e[++c]=(node){x,h[y]};h[y]=c;
    11 } int sg1(int x){return x;}
    12 int sg2(int x){return (x+1)%(s+1)?x&1:2;}
    13 int sg3(int x){return x/s;}
    14 int sg4(int x){
    15     switch(x%4){
    16         case 0: return x-1;
    17         case 3: return x+1;
    18         default : return x;
    19     }
    20 } void init(){
    21     ms(h,0);ms(vis,0);c=0;
    22 } void gs(int x,int fa){
    23     siz[x]=1;
    24     for(int i=h[x],y;i;i=e[i].nxt)
    25     if((y=e[i].y)!=fa&&!vis[y]) 
    26     gs(y,x),siz[x]+=siz[y];
    27 } int gg(int x,int fa){
    28     for(int i=h[x],y;i;i=e[i].nxt)
    29     if((y=e[i].y)!=fa&&!vis[y]&&siz[y]>=hs)
    30     return gg(y,x);return x;
    31 } void dfs(int x,int fa,int o){
    32     tt[nt]=x;tp[nt++]=o;
    33     for(int i=h[x],y;i;i=e[i].nxt)
    34     if((y=e[i].y)!=fa&&!vis[y]) dfs(y,x,o^w[y]);
    35 } struct Hash{
    36     static const int P1=100003,P2=100069;
    37     int h1(int x){return x%P1;}
    38     int h2(int x){return x%P2;}
    39     int t1[P1],t2[P2],st[N],top;
    40     Hash(){ms(t1,-1);ms(t2,-1);}
    41     int find(int x){
    42         return t1[h1(x)]==x||t2[h2(x)]==x;
    43     } void insert(int x){
    44         if(find(x)) return ;
    45         int h=h2(x);st[top++]=x;
    46         if(t2[h]==-1) t2[h]=x;
    47         else while(~x){
    48             h=h1(x);swap(x,t1[h]);
    49             if(x==-1) return ;
    50             h=h2(x);swap(x,t2[h]);
    51         }
    52     } void del(int x){
    53         if(t1[h1(x)]==x) t1[h1(x)]=-1;
    54         else t2[h2(x)]=-1;
    55     } void clear(){
    56         while(top) del(st[--top]);
    57     }
    58 }H;void dc(int x){
    59     gs(x,0);hs=siz[x]>>1;int g;
    60     g=gg(x,0);vis[g]=1;H.insert(0);
    61     for(int i=h[g],y;i;i=e[i].nxt)
    62     if(!vis[y=e[i].y]){
    63         nt=0;dfs(y,0,w[y]);
    64         for(int j=0;j<nt;j++)
    65         if(H.find(w[g]^tp[j]))
    66         {pd=1;break;}
    67         for(int j=0;j<nt;j++)
    68         H.insert(tp[j]);
    69     } H.clear();
    70     for(int i=h[g],y;i&&!pd;i=e[i].nxt)
    71     if(!vis[y=e[i].y]) dc(y);return ;
    72 } int main(){
    73     scanf("%d",&t);while(t--){
    74         init();scanf("%d",&n);
    75         for(int i=1,y,x;i<n;i++)
    76         scanf("%d%d",&x,&y),add(x,y);
    77         for(int i=1;i<=n;i++) 
    78         scanf("%d",&w[i]);scanf("%d",&k);
    79         int (*sg)(int);
    80         if(k==1) sg=sg1;
    81         else if(k==2) scanf("%d",&s),sg=sg2;
    82         else if(k==3) scanf("%d",&s),sg=sg3;
    83         else sg=sg4;pd=0;
    84         for(int i=1;i<=n;i++)
    85         if(!(w[i]=sg(w[i]))) pd=1;
    86         if(!pd) dc(1);
    87         puts(pd?"Mutalisk ride face how to lose?":
    88         "The commentary cannot go on!");
    89     } return 0;
    90 }
    博弈论+点分治
  • 相关阅读:
    范德蒙矩阵相关
    bat运行exe程序
    github 用token远程连接(三)
    为什么将样本方差除以N1?
    Git commit格式 详解(二)
    C++中this与*this的区别
    函数末尾加入const的作用
    git 使用小补充(四)
    人工智能 机器学习
    机器学习分类
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10444393.html
Copyright © 2011-2022 走看看