首页 > 代码库 > 【二分答案】BTP职业网球赛

【二分答案】BTP职业网球赛

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 }

 

【二分答案】BTP职业网球赛