題意:給你兩個數,分別是n和k,每次操作你可以將n-1或者n-2或者n-k,誰不能再次進行操作就輸了;
題解:首先考慮當n<k時,由sg函數易知當n%3==0時,是先手1必敗態,然後當n==k時可以一次去完爲先手必勝,當n>k時,對於之後的數後繼狀態就會增加一個n-k,但是當k%3!=0時,對當前狀態沒有影響,當前狀態是3的倍數時,新增加的狀態必不可能是0,所以當前還是先手必敗,對於當前轉態不是3的倍數時,由於左邊的後繼狀態過來已經是先手必勝了,所以新增加的狀態對其沒有影響,當k是3的倍數時,在新增加的狀態就會對其產生影響,使其不爲0,所以就需要對k是3的倍數時的sg進行打表,通過1打表易得從k+1開始會有k/3-1個0 1 2和一個0 1 2 3,然後一直重複;
打表:
void getsg(int k){
sg[0]=0;
sg[1]=1;
int fa[5];
for(int a=2;a<k;a++)
sg[a]=3-sg[a-1]-sg[a-2];
for(int b=k;b<=3609;b++){
memset(fa,0,sizeof(fa));
fa[sg[b-1]]=1;
fa[sg[b-2]]=1;
fa[sg[b-k]]=1;
sg[b]=0;
while(fa[sg[b]])
sg[b]++;
}
//for(int a=k+1;a<=3609;a++)
//printf("%d\n",sg[a]);
}
AC代碼:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
const int maxn1=1e9;
int read(){
int x=0,w=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')w=0,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
int sg[maxn];
void getsg(int k){
sg[0]=0;
sg[1]=1;
int fa[5];
for(int a=2;a<k;a++)
sg[a]=3-sg[a-1]-sg[a-2];
for(int b=k;b<=3609;b++){
memset(fa,0,sizeof(fa));
fa[sg[b-1]]=1;
fa[sg[b-2]]=1;
fa[sg[b-k]]=1;
sg[b]=0;
while(fa[sg[b]])
sg[b]++;
}
//for(int a=k+1;a<=3609;a++)
//printf("%d\n",sg[a]);
printf("%d\n",sg[3609]);
}
int main( )
{
/*while(1){
int n=read();
getsg(n);
}*/
//freopen("food.in","r",stdin);
//freopen("food.out","w",stdout);
int t=read();
while(t--){
int n=read(),k=read();
if(n==k)
printf("Alice\n");
else if(k%3==0&&k<n){
//printf("%d %d\n",n,k);
int m=k/3;
n=n-k-1;
int num=(m-1)*3+4;
n%=num;
//printf("%d %d")
if(n<=(m-1)*3){
n%=3;
if(n==0)
printf("Bob\n");
else
printf("Alice\n");
}
else{
n-=(m-1)*3;
if(n==0)
printf("Bob\n");
else
printf("Alice\n");
}
}
else{
//printf("1\n");
n%=3;
if(n==0)
printf("Bob\n");
else
printf("Alice\n");
}
}
}