A:水
B:同水,比赛的时候我用了个比较渣的贪心,虽然过了但不是很好。有种更好的贪心方案,把a的求和,如果sum>500 sum-1000即可然后选G,剩下的选A即可,显然不会出现无解情况
C:只需把所有情况都列出来即可,我们会发现00变不成任何其他数字,01,11,10可以互变,判断程度和00情况即可
D:博弈,比赛时着急,没成功YY对,117个点貌似过到81个点挂了。比赛完仔细想想,明白了。n=1显然,n=2其实就是个威佐夫博弈,n=3,想明白了,其实就是个nim博弈。nim博弈之所以用异或,是可以把每堆石子数都拆成二进制,当且仅当每位石子和均为偶数先手必败,也就是所谓的平衡位。先手可以在非平衡状态取胜,因为在非平衡状态,先手总可以取完后使其变成平衡状态,而后手最后一次在平衡状态取石子后,先手即可一次性取完。而此题还有另一种取法,所有堆取相同石子数。所以在平衡状态同时取3堆不可能依旧保持平衡,依旧满足nim博弈。所以,异或即可。此题数据范围较小,DP表状态也可。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int num[5];
int main()
{
int i,n,N;
scanf("%d",&N);
for(i=1;i<=N;++i)
scanf("%d",&num[i]);
if(N==1)
{
if(num[1]!=0)
printf("BitLGM");
else printf("BitAryo");
}
else if(N==2) //威佐夫博弈
{
int a,b;
a=num[1],b=num[2];
double x=(1+sqrt(5.0))/2;
double y=(3+sqrt(5.0))/2;
if(a>b) swap(a,b);
n=ceil(b/y);
int big;
big=n*y;
int sm;
sm=n*x;
if(sm==a && big==b)
printf("BitAryo");
else printf("BitLGM");
}
else if(N==3)//就是nim博弈
{
if((num[1]^num[2]^num[3])==0)
printf("BitAryo");
else printf("BitLGM");
}
return 0;
}
E:trie树,之前一直懒得学,这次比赛完才写出来,算是写过的第一道trie题吧。建一个trie树,存放前缀,然后查询每个后缀与前缀最大异或值即可。显然如果有重叠的话,重叠元素异或后值为0,所以正确答案必定已经计算过。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=100005;
typedef long long LL;
int son[N*40][2];
LL a[N],tot;
inline void add(LL x)
{
int i;
int p=0;
for(i=40;i>=0;--i) //trie树,存放前缀
{
int num=(x>>i)&1;
if(!son[p][num]) son[p][num]=++tot;
p=son[p][num];
}
}
inline LL get(LL x)
{
int i;
int p=0;
LL tmp=0ll;
for(i=40;i>=0;--i)
{
int num=(x>>i)&1;
if(son[p][!num]) {p=son[p][!num];tmp+=1LL<<i;}
else p=son[p][num];
}
return tmp;
}
int main()
{
int i,n;
scanf("%d",&n);
LL s=0ll;
for(i=1;i<=n;++i)
{
scanf("%I64d",&a[i]);
s=s^a[i];
add(s);
}
s=0ll;
LL ans=get(0);
for(i=n;i>=1;--i)
{
s=s^a[i];
ans=max(ans,get(s));
}
printf("%I64d",ans);
return 0;
}