原题地址:A. Tenzing and Tsondu
洛谷上此题地址
Tsondu
和 Tenzing
轮流进行操作,对于每次操作,为了使自己赢的可能性最大,那么他肯定要用自己的最大值和对方的最小值进行操作,于是就得到了如下最直接的做法:#include
int a[100],b[100];
void f(){
int n,m;
scanf("%d%d",&n,&m);
int n1=n,m1=m;//Tsondu和Tenzing手中剩下的数的个数
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
for(int i=1;i<=m;++i) scanf("%d",&b[i]);
int max,maxi,min,mini;
while(n1||m1){
max=a[1],maxi=1;
for(int i=2;i<=n;++i) if(a[i]>max) max=a[i],maxi=i;//求出最大值及其位置
min=1e9+1;
for(int i=1;i<=m;++i) if(b[i]<min&&b[i]) min=b[i],mini=i;//求出最小值及其位置
a[maxi]=max-min,b[mini]=min-max;//更新这两个数的值
if(a[maxi]<=0) a[maxi]=0,n1--;
if(b[mini]<=0) b[mini]=0,m1--;
if(!m1||!n1) break;//有人没数了就退出
//双方对调再来一次
max=b[1],maxi=1;
for(int i=2;i<=n;++i) if(b[i]>max) max=b[i],maxi=i;
min=1e9+1;
for(int i=1 ;i<=m;++i) if(a[i]<min&&a[i]) min=a[i],mini=i;
b[maxi]=max-min,a[mini]=min-max;
if(b[maxi]<=0) b[maxi]=0,m1--;
if(a[mini]<=0) a[mini]=0,n1--;
}
if(n1) printf("Tsondu\n");
else if(m1) printf("Tenzing\n");
else printf("Draw\n");
}
int main(){
int t;
scanf("%d",&t);
while(t--) f();
return 0;
}
优先队列
,但是优先队列要么查询最大值,要么查询最小值,而很难做到一会儿查询最大值,一会儿查询最小值,而用两个优先队列又很难做到相互关联(二叉搜索树
#include
const int maxn=1e6+5;
struct node{
int fa;//父亲
int l,r;//左右儿子
int v;//权值
}a[maxn],b[maxn];
int cnt,cnt1,root,root1;
int read(){//快读
char c=getchar();
int x=0,f=0;
while(c<'0'||c>'9') c=getchar(),f=c=='-'?-1:1;
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return f?-x:x;
}
void insert(int rt,int v){//插入
if(!root){//如果没有根节点,就让他变成根
root=++cnt;
a[root].v=v;
return;
}
if(v<a[rt].v){
if(!a[rt].l){
a[rt].l=++cnt;
a[cnt].v=v;
a[cnt].fa=rt;
}
else insert(a[rt].l,v);
}
else{
if(!a[rt].r){
a[rt].r=++cnt;
a[cnt].v=v;
a[cnt].fa=rt;
}
else insert(a[rt].r,v);
}
}
int qmax(int rt){//查询最大值
if(a[rt].r) return qmax(a[rt].r);
return a[rt].v;
}
int qmin(int rt){//查询最小值
if(a[rt].l) return qmin(a[rt].l);
return a[rt].v;
}
void shanchu(int rt,int v){//删除
if(v>a[rt].v) shanchu(a[rt].r,v);
if(v<a[rt].v) shanchu(a[rt].l,v);
if(v==a[rt].v){
int fa=a[rt].fa;
if(!a[rt].l&&!a[rt].r){//如果没有儿子就直接删掉
if(rt==a[fa].r) a[fa].r=0;
if(rt==a[fa].l) a[fa].l=0;
if(rt==root) root=0;//如果是根节点就要让根变成0
return;
}
if(a[rt].l&&!a[rt].r){//如果只有左儿子,就把左儿子直接接到父节点上
if(rt==root){
root=a[rt].l;
return;
}
if(rt==a[fa].r) a[fa].r=a[rt].l;
if(rt==a[fa].l) a[fa].l=a[rt].l;
a[a[rt].l].fa=fa;//更新父子关系
return;
}
if(a[rt].r&&!a[rt].l){//如果只有右儿子,就把右儿子直接接到父节点上
if(rt==root){
root=a[rt].r;
return;
}
if(rt==a[fa].r) a[fa].r=a[rt].r;
if(rt==a[fa].l) a[fa].l=a[rt].r;
a[a[rt].r].fa=fa;//更新父子关系
return;
}
//如果既有左儿子又有右儿子,
//那么可以用左子树的最大值(或者右子树的最小值)代替它
//再把子树的最大值(或者右子树的最小值)删掉
int ma=qmax(a[rt].l);
shanchu(a[rt].l,ma);
a[rt].v=ma;
}
}
//第二棵二叉搜索树同理
void insert1(int rt,int v){//插入
if(!root1){
root1=++cnt1;
b[root1].v=v;
return;
}
if(v<b[rt].v){
if(!b[rt].l){
b[rt].l=++cnt1;
b[cnt1].v=v;
b[cnt1].fa=rt;
}
else insert1(b[rt].l,v);
}
else{
if(!b[rt].r){
b[rt].r=++cnt1;
b[cnt1].v=v;
b[cnt1].fa=rt;
}
else insert1(b[rt].r,v);
}
}
int qmax1(int rt){//查询最大值
if(b[rt].r) return qmax1(b[rt].r);
return b[rt].v;
}
int qmin1(int rt){//查询最小值
if(b[rt].l) return qmin1(b[rt].l);
return b[rt].v;
}
void shanchu1(int rt,int v){//删除
if(v>b[rt].v) shanchu1(b[rt].r,v);
if(v<b[rt].v) shanchu1(b[rt].l,v);
if(v==b[rt].v){
int fa=b[rt].fa;
if(!b[rt].l&&!b[rt].r){
if(rt==root1) root1=0;
if(rt==b[fa].r) b[fa].r=0;
if(rt==b[fa].l) b[fa].l=0;
return;
}
if(b[rt].l&&!b[rt].r){
if(rt==root1){
root1=b[rt].l;
return;
}
if(rt==b[fa].r) b[fa].r=b[rt].l;
if(rt==b[fa].l) b[fa].l=b[rt].l;
b[b[rt].l].fa=fa;
return;
}
if(b[rt].r&&!b[rt].l){
if(rt==root1){
root1=b[rt].r;
return;
}
if(rt==b[fa].r) b[fa].r=b[rt].r;
if(rt==b[fa].l) b[fa].l=b[rt].r;
b[b[rt].r].fa=fa;
return;
}
int ma=qmax1(b[rt].l);
shanchu1(b[rt].l,ma);
b[rt].v=ma;
}
}
void f(){
int n=read(),m=read(),ma=0,mi=0;
for(int i=1;i<=n;++i) insert(root,read());//建树
for(int i=1;i<=m;++i) insert1(root1,read());
while(1){
ma=qmax(root);
mi=qmin1(root1);
if(!ma&&!mi){//同时变成了0,平局
printf("Draw\n");
break;
}
if(!ma){//Tenzing win
printf("Tenzing\n");
break;
}
if(!mi){//Tsondu win
printf("Tsondu\n");
break;
}
shanchu(root,ma),shanchu1(root1,mi);//删除原先的数
if(ma>mi) insert(root,ma-mi);
if(ma<mi) insert1(root1,mi-ma);//加入新的数
//双方对调再来一次
ma=qmax1(root1);
mi=qmin(root);
if(!ma&&!mi){
printf("Draw\n");
break;
}
if(!mi){
printf("Tenzing\n");
break;
}
if(!ma){
printf("Tsondu\n");
break;
}
shanchu1(root1,ma),shanchu(root,mi);
if(ma>mi) insert1(root1,ma-mi);
if(ma<mi) insert(root,mi-ma);
}
for(int i=1;i<=cnt;++i) a[i].fa=a[i].l=a[i].r=a[i].v=0;
for(int i=1;i<=cnt1;++i) b[i].fa=b[i].l=b[i].r=b[i].v=0;
cnt=cnt1=0,root=root1=0;
}
int main(){
int t=read();
while(t--) f();
return 0;
}
平衡树
来解决,这里就不讲了数学题
x=max(x-y,0)=x-min(x,y)
y=max(y-x,0)=y-min(x,y)
winer
!#include
int read(){//快读
char c=getchar();
int x=0,f=0;
while(c<'0'||c>'9') c=getchar(),f=c=='-'?-1:1;
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return f?-x:x;
}
void f(){
int n=read(),m=read();
long long s=0,s1=0;//50*1e9会爆int !!!
for(int i=1;i<=n;++i) s+=read();//求和
for(int i=1;i<=m;++i) s1+=read();
if(s==s1) printf("Draw\n");//比较
if(s<s1) printf("Tenzing\n");
if(s>s1) printf("Tsondu\n");
}
int main(){
int t=read();
while(t--) f();
return 0;
}