题目
问题描述
大意是有A、B两个人轮流发球(不会因为胜负情况而改变顺序),在每局游戏中,若发球方胜利则被称该玩家保持了发球(但不会影响发球权的交替),若接球方胜利则称该玩家打破了发球。
每次会给定A,B分别的获胜次数a,b(不存在平局的情况),问总共可能出现过几次玩家打破发球的情况。
分析
int x=(a+b)/2;
int y=a+b-x;
由于发球权是不断交替的,所以对于玩家A来说,发球的次数要么为x次,要么为y次。
当发球次数为x次时,已知A获胜了a次,a次胜利是由发球获胜和接球获胜两种情况组成的,若在发球中赢了i次,那么就意味着在接球中赢了(a-i)次:
发球中的失败次数即B打破了发球,接球中的胜利次数即A打破了发球,
a
n
s
.
i
n
s
e
r
t
(
x
−
i
+
a
−
i
)
ans.insert(x-i+a-i)
ans.insert(x−i+a−i)就可以统计出当前情况下的打破发球的次数。
当然一定要满足
i
<
=
x
&
&
(
a
−
i
)
<
=
y
i<=x\&\&(a-i)<=y
i<=x&&(a−i)<=y保证获胜次数要小于等于进行的场数。
处理完之后,还需要重新再处理一遍当A的发球次数为y时的情况,过程仍然一致。
然后对其进行枚举即可,为了去重和便于输出结果,这里使用了集合来操作。
代码
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
set<int> f(int a,int b){
int x=(a+b)/2;
int y=a+b-x;
set<int>ans;
for(int i=0;i<=a;i++){
if(i<=x&&(a-i)<=y){
ans.insert(x-i+a-i);
}
}
swap(x,y);
for(int i=0;i<=a;i++){
if(i<=x&&(a-i)<=y){
ans.insert(x-i+a-i);
}
}
return ans;
}
int main(){
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
set<int>ans;
ans=f(a,b);
cout<<ans.size()<<endl;
int tmp=ans.size();
for(auto it=ans.begin();it!=ans.end();it++){
cout<<(*it)<<" ";
}
cout<<endl;
}
return 0;
}