CF786A - Berzerk
1 /* 2 CF786A - Berzerk 3 http://codeforces.com/contest/786/problem/A 4 博弈论 5 直接搜出NP状态图。记得要记忆化剪枝。 6 * 7 */ 8 #include <cstdio> 9 #include <cstring> 10 //#define tle 11 #ifdef tle 12 //#define test 13 14 using namespace std; 15 const int Nmax=7005; 16 int now; 17 int is[2][Nmax]; 18 int n; 19 int s[2][Nmax]; 20 int tmp[2][Nmax]; 21 int k[2]; 22 #ifdef test 23 void watch() 24 { 25 for(int i=0;i<=1;i++) 26 { 27 printf("s[%d]:\n",i); 28 for(int j=1;j<=n;j++) 29 printf("%d ",is[i][j]); 30 printf("\n"); 31 } 32 } 33 #endif 34 35 void work() 36 { 37 for(int j=0;j<=1;j++) 38 for(int i=1;i<=k[j];i++) 39 { 40 int x=(n+1-s[j][i])%n; 41 while(x<=0) 42 x+=n; 43 is[j][x]=1; 44 } 45 #ifdef test 46 watch(); 47 #endif 48 49 for(int t=1;t<=100000;t++) 50 { 51 for(int ii=0;ii<=1;ii++) 52 for(int jj=1;jj<=n;jj++) 53 tmp[ii][jj]=is[ii][jj]; 54 for(int now=0;now<=1;now++) 55 for(int i=2;i<=n;i++) 56 { 57 if(is[now][i]!=-1) 58 continue; 59 int flag=0; 60 for(int j=1;j<=k[now];j++) 61 { 62 int x=(i+s[now][j])%n; 63 while(x<=0) 64 x+=n; 65 if(is[now^1][x]==0) 66 { 67 is[now][i]=1; 68 flag=1; 69 break; 70 } 71 if(is[now^1][x]==-1) 72 flag=1;//标记不是P态 73 } 74 if(!flag) 75 is[now][i]=0; 76 #ifdef test 77 printf("is[%d][%d]:\n",now,i); 78 watch(); 79 #endif 80 81 } 82 int ff=0; 83 for(int ii=0;ii<=1;ii++) 84 { 85 if(ff) 86 break; 87 for(int jj=1;jj<=n;jj++) 88 if(tmp[ii][jj]!=is[ii][jj]) 89 { 90 ff=1; 91 break; 92 } 93 } 94 if(!ff) 95 break; 96 } 97 98 } 99 100 void init() 101 { 102 for(int i=1;i<=n;i++) 103 is[0][i]=is[1][i]=-1; 104 is[0][1]=is[1][1]=1; 105 } 106 int main() 107 { 108 scanf("%d",&n); 109 for(int i=0;i<=1;i++) 110 { 111 scanf("%d",&k[i]); 112 for(int j=1;j<=k[i];j++) 113 scanf("%d",&s[i][j]); 114 } 115 init(); 116 work(); 117 for(int t=0;t<=1;t++) 118 { 119 for(int i=2;i<=n;i++) 120 { 121 if(i!=2) 122 printf(" "); 123 if(is[t][i]==-1) 124 printf("Loop"); 125 else if(is[t][i]==0) 126 printf("Lose"); 127 else 128 printf("Win"); 129 } 130 printf("\n"); 131 } 132 } 133 #endif 134 135 using namespace std; 136 const int Nmax=7005; 137 int now; 138 int is[2][Nmax]; 139 int n; 140 int s[2][Nmax]; 141 int tmp[2][Nmax]; 142 int k[2]; 143 144 void dfs(int now,int x,int sstatus) 145 { 146 if(is[now][x]!=-1)//如果已经有状态了,返回 147 return; 148 is[now][x]=sstatus; 149 if(sstatus==0)//如果当前点为必败态,则让与其相接的点为必胜态 150 { 151 for(int i=1;i<=k[now^1];i++) 152 { 153 int next=(x-s[now^1][i])%n; 154 while(next<=0) 155 next+=n; 156 dfs(now^1,next,1); 157 } 158 } 159 if(sstatus==1)//如果当前点为必胜态,则让与其相接的点的非必胜态边个数-1 160 { 161 for(int i=1;i<=k[now^1];i++) 162 { 163 int next=(x-s[now^1][i])%n; 164 while(next<=0) 165 next+=n; 166 tmp[now^1][next]--;//利用tmp数组记录当前相接的点的非必胜态个数来剪枝,如果相邻点都是必胜态,则当前点为必败态 167 if(!tmp[now^1][next]) 168 dfs(now^1,next,0); 169 } 170 } 171 } 172 173 void init() 174 { 175 for(int i=1;i<=n;i++) 176 is[0][i]=is[1][i]=-1; 177 is[0][1]=is[1][1]=0; 178 } 179 int main() 180 { 181 scanf("%d",&n); 182 for(int i=0;i<=1;i++) 183 { 184 scanf("%d",&k[i]); 185 for(int j=1;j<=k[i];j++) 186 scanf("%d",&s[i][j]); 187 for(int j=1;j<=n;j++) 188 tmp[i][j]=k[i]; 189 } 190 init(); 191 for(int j=0;j<=1;j++) 192 for(int i=1;i<=k[j];i++) 193 { 194 int x=(n+1-s[j][i])%n; 195 while(x<=0) 196 x+=n; 197 dfs(j,x,1); 198 } 199 for(int t=0;t<=1;t++) 200 { 201 for(int i=2;i<=n;i++) 202 { 203 if(i!=2) 204 printf(" "); 205 if(is[t][i]==-1) 206 printf("Loop"); 207 else if(is[t][i]==0) 208 printf("Lose"); 209 else 210 printf("Win"); 211 } 212 printf("\n"); 213 } 214 return 0; 215 }