首先这道题一看就是一道裸裸的集合-Nim游戏。
关键在于必胜态的情况下面那两个数怎么输出了。
我这里小提一下集合Nim游戏的解题方式:
对每一堆石子求他的sg值,再把每一堆的sg值^起来就行。
所以很明显对于
sg(a1)^sg(a2)^...^sg(an)=res
如果res≠0,说明就是必胜态,等于0说明是必败态。
必胜态的时候,该怎么取石子呢?
很明显,必胜态要必胜的情况下,必须是取完后把必胜态转为必败态。
即(假如在ai堆中取了x个石子)
sg(a1)^sg(a2)^...^sg(ai-x)^...^sg(an)=0;
即在ai堆取完x个石子后就变成必败态了。
那么如何找到这个x呢。
由于sg(a1)^sg(a2)^...^sg(an)=res;
所以sg(a1)^sg(a2)^...^sg(ai-1)^sg(ai+1)^...^sg(an)=res^sg(ai);
所以原式就等于找到res^sg(ai)^sg(ai-x)==0这样的点就行。
其中i就是第i堆,a[i]就是第i堆中原本的石子个数,x就是取的石子个数。
由于n和m的范围都很小,直接暴力就行。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1005;
int f[maxn];
int a[15],b[15];
int n,m;
int sg(int x)
{
if(f[x]!=-1) return f[x];
set<int> sets;
for(int i=1;i<=m;i++)
if(x>=b[i])
sets.insert(sg(x-b[i]));
for(int i=0;;i++)
if(!sets.count(i))
return f[x]=i;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
memset(f,-1,sizeof(f));
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>m;
for(int i=1;i<=m;i++) cin>>b[i];
int res=0;
vector<int> head;
for(int i=1;i<=n;i++)
{
res^=sg(a[i]);
}
if(res)
{
cout<<"YES"<<endl;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i]>=b[j])
{
if((res^sg(a[i])^sg(a[i]-b[j]))==0)
{
cout<<i<<" "<<b[j]<<endl;
return 0;
}
}
}
}
}
else cout<<"NO"<<endl;
return 0;
}