题目
问题描述
分析
采用 S G SG SG函数的思路,自后向前得出每个位置的状态(必胜态/必败态)。
假设有两个位置
i
i
i与
j
j
j,且满足
i
<
j
i<j
i<j与
A
i
=
=
A
j
A_i==A_j
Ai==Aj:
若
F
j
=
0
F_j=0
Fj=0(必败态),则由位置
i
i
i走到此处为最优策略,也就是
F
i
=
1
F_i=1
Fi=1;
若
F
j
=
1
F_j=1
Fj=1(必胜态),则于位置
j
j
j右侧必存在位置
k
k
k满足
F
k
=
0
F_k=0
Fk=0,那么由位置
i
i
i走到
k
k
k为最优策略,
F
i
=
1
F_i=1
Fi=1依然成立。
所以在满足 i < j i<j i<j与 A i = = A j A_i==A_j Ai==Aj的条件下, F i = 1 F_i=1 Fi=1始终成立,也就是说对于值 A i A_i Ai来说,如果它不是该类值在该序列中的最右端的那个,那么就处于必胜态。
但如果位置
A
i
A_i
Ai恰是该类值在该序列中的最右端的那个,采用直接DP可以求值。
由每类中位于最右端的点构成的集合中,位于最右端的那个位置的状态一定是必败态,因为这个点已经无法再向右移动,就由这个点来倒推其余的点,处理位于次右端的点,依次类推。
priority_queue<ll, vector<ll>, less<ll> >q;
memset(sg,1,sizeof sg);
fir(i,0,255){
if(a[i])q.push(a[i]);
}
while(!q.empty()){
ll tmp=b[q.top()];
fir(i,0,7){
if(sg[tmp^(1<<i)]==0){
sg[tmp]=1;
break;
}
}
if(sg[tmp]!=1)sg[tmp]=0;
q.pop();
}
代码
#include<bits\stdc++.h>
using namespace std;
typedef long long ll;
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
#define rif(i, a, b) for (int i = (a); i >= (b); i--)
const ll N=4e5+5;
ll n,m,cnt;
ll a[256],b[N],sg[256];
void f(){
priority_queue<ll, vector<ll>, less<ll> >q;
memset(sg,1,sizeof sg);
fir(i,0,255){
if(a[i])q.push(a[i]);
}
while(!q.empty()){
ll tmp=b[q.top()];
fir(i,0,7){
if(sg[tmp^(1<<i)]==0){
sg[tmp]=1;
break;
}
}
if(sg[tmp]!=1)sg[tmp]=0;
q.pop();
}
}
int main(){
cin>>n>>m;
fir(i,1,n){
ll tmp;
cin>>tmp;
b[i]=tmp;
a[tmp]=i;
}
cnt=n;
while(m--){
ll tmp,k;
cin>>tmp>>k;
if(tmp==1){
b[++cnt]=k;
a[k]=cnt;
}
else if(tmp==2){
if(a[b[k]]!=k)cout<<"Grammy"<<endl;
else{
f();
if(sg[b[k]])cout<<"Grammy"<<endl;
else cout<<"Alice"<<endl;
}
}
}
}