codeforces 496D Tennis Game(枚举)

题目链接

Tennis Game
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Petya and Gena love playing table tennis. A single match is played according to the following rules: a match consists of multiple sets, each set consists of multiple serves. Each serve is won by one of the players, this player scores one point. As soon as one of the players scores t points, he wins the set; then the next set starts and scores of both players are being set to 0. As soon as one of the players wins the total of s sets, he wins the match and the match is over. Here s and t are some positive integer numbers.

To spice it up, Petya and Gena choose new numbers s and t before every match. Besides, for the sake of history they keep a record of each match: that is, for each serve they write down the winner. Serve winners are recorded in the chronological order. In a record the set is over as soon as one of the players scores t points and the match is over as soon as one of the players wins s sets.

Petya and Gena have found a record of an old match. Unfortunately, the sequence of serves in the record isn't divided into sets and numbers s and t for the given match are also lost. The players now wonder what values of s and t might be. Can you determine all the possible options?

Input

The first line contains a single integer n — the length of the sequence of games (1 ≤ n ≤ 105).

The second line contains n space-separated integers ai. If ai = 1, then the i-th serve was won by Petya, if ai = 2, then the i-th serve was won by Gena.

It is not guaranteed that at least one option for numbers s and t corresponds to the given record.

Output

In the first line print a single number k — the number of options for numbers s and t.

In each of the following k lines print two integers si and ti — the option for numbers s and t. Print the options in the order of increasingsi, and for equal si — in the order of increasing ti.

Sample test(s)
input
5
1 2 1 2 1
output
2
1 3
3 1
input
4
1 1 1 1
output
3
1 4
2 2
4 1
input
4
1 2 1 2
output
0
input
8
2 1 2 1 1 1 1 1
output
3
1 6
2 3
6 1

题意:两个人打乒乓球,已知每一个球是谁赢,但是不知道,一个局赢多少个球算赢(设为t),也不知道赢多少局(设为s)算赢得最后的胜利。按字典序,输出所有可能的s和t。

题解:枚举t,1<=t<=n。对于每一个枚举的t,再O(n)扫一遍,判断是否可行并求出对应的s。这样复杂度显然是不行的。但是我们可以预处理出每个1的位置和每个2的位置。这样就可以O(1)枚举出每一局,就不用O(n)扫一遍而是最多O(n/t)扫一遍。

复杂度为O(n*(1+1/2+1/3+....1/n))约等于O(nlgn)。

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<stdlib.h>
#include<vector>
#define inff 0x3fffffff
#define nn 110000
#define mod 1000000007
typedef long long LL;
const LL inf64=inff*(LL)inff;
using namespace std;
int n;
int yi[nn],er[nn];
vector<pair<int,int> >ans;
int a[nn];
int f1[nn],f2[nn];
int main()
{
    int i,x;
    int i1,i2,j;
    while(scanf("%d",&n)!=EOF)
    {
        i1=i2=0;
        ans.clear();
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            x=a[i];
            if(x==1)
            {
                yi[++i1]=i;
            }
            else
                er[++i2]=i;
        }
        f1[n+1]=i1+1;
        f2[n+1]=i2+1;
        int ix,fc;
        ix=i1,fc=i2;
        for(i=n;i>=1;i--)
        {
            if(a[i]==1)
            {
                f1[i]=ix--;
                f2[i]=f2[i+1];
            }
            else
            {
                f2[i]=fc--;
                f1[i]=f1[i+1];
            }
        }
        int fi,se;
        int one,two;
        for(i=1;i<=n;i++)
        {
            fi=se=0;
            ix=fc=1;
            for(j=1;j<=n;)
            {
                if(ix+i-1>i1)
                    one=inff;
                else
                    one=yi[ix+i-1];
                if(fc+i-1>i2)
                    two=inff;
                else
                    two=er[fc+i-1];
                if(one==inff&&two==inff)
                    break;
                if(one<two)
                {
                    j=one+1;
                    fi++;
                    ix+=i;
                    fc=f2[j];
                }
                else
                {
                    j=two+1;
                    se++;
                    fc+=i;
                    ix=f1[j];
                }
            }
            if(j==n+1)
            {
                if(one<two&&fi>se)
                {
                    ans.push_back(make_pair(fi,i));
                }
                if(two<one&&se>fi)
                {
                    ans.push_back(make_pair(se,i));
                }
            }
        }
        int la=ans.size();
        sort(ans.begin(),ans.end());
        printf("%d\n",la);
        for(i=0;i<la;i++)
        {
            printf("%d %d\n",ans[i].first,ans[i].second);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值