问题描述
Gob和Michael常在一起打乒乓球。他们是这样决定比赛的输赢的:比赛由若干大局组成;谁最先赢下s大局谁就获得比赛的胜利;在每一大局中,谁先得t分就获得本大局的胜利。
在一次比赛中,他们只记录了比赛中的每一分是谁得的,但忘记了记录s和t。现在给出比赛的每一分的得分情况,求出所有可能的s和t。Gob保证,得分表是完整的,也就是在比赛恰好在最后一人,得到最后一分后结束。
输入格式(game.in)
第一行一个整数N,代表比赛一共得到了多少分。
第二行N个整数,代表比赛中每一分是谁得到的;1代表Gob,2代表Michael。
输出格式(game.out)
第一行一个整数M,代表共有多少种可能的s,t情况。
接下来M行每行两个整数si, ti,代表一种可能的s,t情况。M种情况按照s从小到大输出;在s相等时按照t从小到大输出。
样例输入1
5
1 2 1 2 1
样例输出1
2
1 3
3 1
样例输入2
5
1 2 2 2 1
样例输出2
0
样例输入3
10
1 1 2 1 1 1 2 2 1 1
样例输出3
3
1 7
3 2
7 1
数据范围与约束
对于50%的数据,N<=1000;
对于100%的数据,1<=N<=100,000。
思路:
一看就是一道搜索题,我也搜了,然而只拿了70分。原来还需要二分的。。。。
(1)先枚举t,从1到n。
(2)算一下两人最后的胜利局数,再结合最后一局是谁赢得来判断是否加到答案序列中。
(3)在查找过程中,二分查找比较快
#include<iostream> #include<queue> #include<math.h> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,a[100009],ans,f1[100009],f2[100009]; struct node{ int s,t; }b[90000]; bool cmp(node A,node B) { return A.s < B.s; return A.t < B.t; } void work(int x) { int np,nq,kp,kq,cp=0,cq=0,last,i; for( i=0;i<n;i) { np=f1[i]+x; nq=f2[i]+x; kp=lower_bound(f1+i,f1+n+1,np)-f1-1; kq=lower_bound(f2+i,f2+n+1,nq)-f2-1; if(kp < kq) cp++,last=1; else cq++,last=2; i=min(kp,kq)+1; } if(cp==cq || i!=n ) return; if(last==1&& cp>cq) b[++ans].t=x,b[ans].s=cp;else if(last==2&& cp<cq) b[++ans].t=x,b[ans].s=cq; return; } int main() { freopen("game.in","r",stdin);freopen("game.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==1) f1[i]++;else f2[i]++; f1[i]+=f1[i-1],f2[i]+=f2[i-1]; } for(int i=1;i<=n;i++) work(i); sort(b+1,b+1+ans,cmp); printf("%d\n",ans); for(int i=1;i<=ans;i++) printf("%d %d\n",b[i].s,b[i].t); return 0; }