目录
A. Chip Game(博弈)
题意:给你了n*m的格子,Tonya和Burenka从左下角出发,两人只能走奇数长度的路.假设两人足够聪明我们如何能够,不能走了的就失败(只能往右或者往上走).
思路:已知我们直接把从左往右和从下往上两条路进行分割,当这两条路为奇数长度可以把它们分成1,否则分成2(因为写一个人改变上一个人的奇偶性,所以奇数相当于上一个人走一步,偶数为两个人都走一步).
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
void solve()
{
int n,m;
cin>>n>>m;
if(n%2==m%2)
cout<<"Tonya"<<endl;
else
cout<<"Burenka"<<endl;
return ;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
B. Mathematical Circus
题意:我们有一个偶数长度n的数组,还有一个k,我们要把数组分成n/2对.每对为(a,b),并且满足(a+k)*b被4整除.问是否可以构造出.
思路:
1.当k为奇数时,已知奇数+奇数=偶数.偶数拥有因子2,两个偶数相乘至少有2个因子2,肯定能被4整除,所以这种情况就之就输出(奇数,偶数)搭配即可.
2.当k为偶数时,我们发现如果含有一个偶数%4=0那么这一组就确定了,(奇数,4的倍数).那么还剩下2的倍数和其他奇数,显然奇数+偶数还是奇数,所以我们要在2的倍数上下功夫.当k不是2的倍数的情况下,(k+2的倍数)肯定是4的倍数.如果k是4的倍数就无法成立.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =2e5+10,mod=998244353;
int a[N],b[N];
void solve()
{
int n,k;
cin>>n>>k;
if(k%2)
{
int f=0;
for(int i=1;i<=n/2;i++)
{
a[i]=i*2-1;
b[i]=i*2;
}
for(int i=1;i<=n/2;i++)
{
if((a[i]+k)*b[i]%4)
{
f=1;
break;
}
}
if(f)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(int i=1;i<=n/2;i++)
cout<<a[i]<<" "<<b[i]<<endl;
}
}
else
{
int f=0;
if(k%4)
{
for(int i=1;i<=n/2;i++)
{
if((i*2)%4)
{
a[i]=i*2;
b[i]=i*2-1;
}
else
{
a[i]=i*2-1;
b[i]=i*2;
}
}
for(int i=1;i<=n/2;i++)
{
if((a[i]+k)*b[i]%4)
{
f=1;
break;
}
}
if(f)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(int i=1;i<=n/2;i++)
cout<<a[i]<<" "<<b[i]<<endl;
}
}
else
cout<<"NO"<<endl;
}
return ;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
C. Fighting Tournament
问题:有n个运动员,q次询问,每次询问包含两个数i,k.意为询问第i位运动员在进行k场比赛的时候会胜利多少场.(比赛规则是取队列前两个队员比赛,胜利者放回队伍前端,失败者在队伍后端)
思路:我们知道,有一个武力值最高的运动员,如果他开始了比赛,俺么后面无论如何比赛他都会一直在队伍的首位并且一直胜利.所以我们先跑一遍循环,对于每个运动员第一次和最后一次胜利进行处理得出来.然后分情况讨论:
1.当当前运动员在最强运动员后面,或者比赛根本比不到他,或者他第一次胜利的场次>k,或者根本没有胜利过的话,这个询问就是直接输出0.
2.当询问的人就是最强运动员时,直接输出k+1-他第一次胜利的场次
3.生育情况直接输出min(k,f[i].second)-f[i].first+1,也就是最后一次胜利和第一次胜利的场次之间共赢了多少场即可.
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =1e5+10,mod=998244353;
int a[N];
void solve()
{
int n,q,maxid=1;
cin>>n>>q;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]>a[maxid])
maxid=i;
}
vector<PII>f(n+1);
int sheng=a[1];
int pos=1;
for(int i=2;i<=n;i++)
{
if(a[i]<sheng)
{
if(f[pos].second==0)
f[pos].first=i-1;
f[pos].second=i-1;
}
else if(a[i]>sheng)
{
sheng=a[i];
pos=i;
f[pos].first=i-1;
f[pos].second=i-1;
}
}
int i,k;
while(q--)
{
cin>>i>>k;
if(i>maxid||k<i-1||f[i].first>k||f[i].first==0)
cout<<"0"<<endl;
else if(i==maxid)
cout<<k+1-f[i].first<<endl;
else
cout<<min(k,f[i].second)-f[i].first+1<<endl;
}
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}
D1.D2. Burenka and Traditions
问题:有一个长为n的数组,我们每次可以选择一个l,r和任意一个x然后花费(l-r+1)/2(向上取整)的能量去让[l,r]之间的数组元素都异或上x,问最少花费多少能量可以把整个数组所有元素化为0.
思路:我们可以贪心的去变化,花费一点能量把遍历位置前一位的数移动到下一位去,例如[1,2,4]变化之后就是[0,3,4]->[0,0,7],用一个f数组记录此时的花费为多少,用一个map记录一下移动之后a[i]的位置在哪里.如果我在进行a[i]的变化之后,a[i]在之前出现过(map判断)那么这一个区间异或和就为0,那么我们直接进行f的状态转移f[i]=max(f[i],f[map[a[i]]]+区间长度).当他为0我们就可以直接往下进行操作而不是把这一位转移到下一位了.
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N =5e5+10,mod=998244353;
int a[N];
int f[N];
void solve()
{
map<int,int>ma;
int n;
cin>>n;
ma[0]=0;
f[0]=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
a[i]^=a[i-1];
f[i]=f[i-1]+1;
if(ma.count(a[i]))
{
f[i]=min(f[i],f[ma[a[i]]]+i-ma[a[i]]-1);
}
ma[a[i]]=i;
}
cout<<f[n]<<endl;
return ;
}
signed main()
{
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
int t;
cin>>t;
while(t--)
solve();
return 0;
}