problem:
http://codeforces.com/problemset/problem/496/D
一场比赛分若干set. 一个set分若干serve。两个人玩,每个serve其中一个人赢。
当一个人赢了t个serve,他就赢了一个set,然后两个人的serve score都清零。
当一个人赢了s个set,这场比赛他就赢了,比赛结束。
现在已知某一场比赛一共有n个serve和每个serve是谁赢的(1 or 2)。问这场比赛可能的s 和 t对。1<=n<=1e5
think:
最后一个serve赢的那个人一定是这场比赛的赢的人。
1.枚举t。t确定了,比赛的全部过程就全都确定了,能否可行以及s就都知道了。
2.已知t的话,找下一个set的时候用二分,不然O(n)的走会超时。已知第i个set的结束位置fr,找第i+1个set的结束位置to,那么就找最左边的to,使得[fr+1,to]有一个人赢了t个serve。如果最后那个set结束位置不是n肯定不行。
3.现在已知t,和整场比赛两个人分别赢的set的次数。看是否赢set最多的人和a[n]是同一个人。是的话这个t,s对是ok的。否则是不ok的。
code:
<pre name="code" class="cpp">const int N = 100100;
int a[N];
int one[N];//前i个有几个1
int two[N];//前i个有几个2
struct point{//最后的答案,最后排序后输出
int x, y;
}p[N];
int n, ans;
bool cmp(point a, point b){
if(a.y == b.y) return a.x < b.x;
return a.y < b.y;
}
void upd(int i, int id, int xx, int yy, int y0){
if(i == n && a[n] == id && yy > y0){
//最后赢的人a[n],一定是结果赢的人。结果赢的人,一定是a[n]
p[ans].x = xx;
p[ans++].y = yy;
}
}
int mid_find(int t, int fr, int to){//二分
if(one[to] - one[fr] < t && two[to] - two[fr] < t) return to + 1;
int L = fr + 1, R = to;
while(L < R){
int M = (L + R) >> 1;
int t1 = one[M] - one[fr];
int t2 = two[M] - two[fr];
if(t1 < t && t2 < t) L = M + 1;
else if(t1 > t || t2 > t) R = M - 1;
else if(t1 == t && t2 == t) R = M - 1;
else if(t1 == t) {
if(a[M] == 1) return M;
else R = M - 1;
}
else{
if(a[M] == 2) return M;
else R = M - 1;
}
}
return L;
}
void check(int t){
int num1 = 0, num2 = 0;
int win1 = 0, win2 = 0;
for(int i = 0; i < n; ){
int ii = mid_find(t, i, n);//第i+1到第ii个是一场比赛,赢的人赢了t局
if(ii > n) return ;
num1 = one[ii] - one[i];
num2 = two[ii] - two[i];
if(num1 == t) {
++win1;
upd(ii, 1, t, win1, win2);
}
else if(num2 == t){
++win2;
upd(ii, 2, t, win2, win1);
}
i = ii;
}
}
int main(){
while(scanf("%d", &n) != EOF){
one[0] = 0;
two[0] = 0;
int m = 0;
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if(a[i] == 1) {
++m;
one[i] = one[i - 1] + 1;
two[i] = two[i - 1];
} else {
one[i] = one[i - 1];
two[i] = two[i - 1] + 1;
}
}
if(a[n] == 2) m = n - m;
ans = 0;
for(int i = 1; i <= m; ++i){
check(i);
}
printf("%d\n", ans);
sort(p, p + ans, cmp);
for(int i = 0; i < ans; ++i) printf("%d %d\n", p[i].y, p[i].x);
}
return 0;
}