【二分答案】BTP职业网球赛
版权声明:本篇随笔版权归作者Etta(http://www.cnblogs.com/Etta/)所有,转载请保留原地址!
Description
参加职业网球赛的奶牛们有着职业牛网球赛协会(BTP)的排名。
有时候,预测一场网球赛的结果是可能的。
如果参赛的两头牛排名之间的差距大于一个给定的常数K(0<=K<=N-1),即|Rank1-Rank2|>K(其中Rank1,Rank2分别表示奶牛1与奶牛2的排名),那么排名较高的奶牛总是会赢得比赛的胜利。
下周将有一个大型的淘汰赛制的赛事,有N(N=2^t,t<=16,t∈N)头奶牛参赛,产生一个冠军。在第一轮,N/2对选手进行比赛,获胜的N/2个选手进入下一轮。
同样,下面的每轮比赛中,都是获胜的一半进入下一轮,直到只剩一头牛。
场外的牛们在对比赛下赌注,想知道随着一轮一轮的比赛,最后有可能夺冠的牛中排名最低的牛的排名。
你的工作就是计算这个最低排名,并且给出一种能使这头牛获胜的场次安排。
Input
第1行:两个空格隔开的数N和K。
Output
一行一个整数,即所有可能夺冠的牛中排名最低的牛的排名。
Sample Input
16 3
Sample Output
11
Solution
可以证明如果排名为X的选手最终获胜,那么排名在X前的选手也可以获胜(详见论文杨俊《浅谈二分策略的应用》)。所以可以开心地二分答案了,用并查集倒推比赛序列判断答案是否可行。
Code
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 using namespace std; 5 6 const int A=500010; 7 8 int n,k,t,r,l,p,q,ss,tot,tmp; 9 int ex[A],nxt[A],line[A];//nxt[]表示从i起未被刷的奶牛 10 11 int find(int x) 12 { 13 if(x!=nxt[x])nxt[x]=find(nxt[x]); 14 return nxt[x]; 15 } 16 17 bool pan(int R) 18 { 19 for(int i=1;i<=n+1;++i)nxt[i]=i;//循环至n+1保证当方案不可行时能够判断 20 nxt[R]=R+1; 21 tot=ss=1; 22 line[tot]=R; 23 24 for(int i=1;i<=t;++i) 25 { 26 for(int j=1;j<=ss;++j) 27 { 28 p=line[j]; 29 q=find(max(1,p-k)); 30 if(q>n)return false; 31 nxt[q]=nxt[q+1]; 32 line[++tot]=q; 33 } 34 ss=tot;//细节 35 } 36 return true; 37 } 38 39 void erfen(int l,int r) 40 { 41 int mid; 42 while(l!=r) 43 { 44 mid=((l+r)>>1)+1; 45 if(pan(mid))l=mid; 46 else r=mid-1; 47 } 48 printf("%d\n",l); 49 } 50 51 int main() 52 { 53 freopen("competition.in","r",stdin); 54 freopen("competition.out","w",stdout); 55 scanf("%d%d",&n,&k); 56 tmp=n; 57 while(!(tmp&1)){tmp>>=1;++t;}//计算log以2为底n的对数 58 l=1;r=n; 59 erfen(l,r); 60 return 0; 61 }