[Codeforces 496D] Tennis Game (筛法复杂度)

Codeforces - 496D

给定一个长度为 N的网球比赛的记录
网球比赛胜者要赢 S场,每场胜者要赢 T球
问所有符合条件的 S和 T的可能取值


枚举 T的值,然后判断是否有符合条件的 S
通过二分来查找每场的结束位置
总的复杂度为 (Nlog(N)log(N))

关于 s是否合法,有挺多条件的,我刚开始没想周全

  1. 如果在二分最后一场的时候,没有人能赢 T球,则不合法
  2. 最后双方胜场数一样,不合法
  3. 胜场数较多的那个人,与最后一场的胜者不是一个人,不合法
#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
#include <complex>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n----------")

const int maxn=1e5+10;
int N;
int in[maxn], psum[2][maxn];

int solve(int);

int main()
{
    #ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
    #endif

    while(~scanf("%d", &N))
    {
        vector<Pii> ans;
        for(int i=1; i<=N; i++)
        {
            scanf("%d", &in[i]);
            psum[0][i] = psum[0][i-1];
            psum[1][i] = psum[1][i-1];
            psum[in[i]-1][i]++;
        }
        for(int t=1,s; t<=N; t++)
        {
            s = solve(t);
            if(~s) ans.push_back({s,t});
        }
        sort(ans.begin(), ans.end());
        cout << ans.size() << "\n";
        for(Pii now:ans) cout << now.first << " " << now.second << "\n";
    }
    return 0;
}

int solve(int t)
{
    int p=0, s[2]={0}, last=0;
    while(p<N)
    {
        int p1 = lower_bound(psum[0]+p+1, psum[0]+N+1, psum[0][p]+t) - psum[0];
        int p2 = lower_bound(psum[1]+p+1, psum[1]+N+1, psum[1][p]+t) - psum[1];
//      printf("p1:%d p2:%d\n", p1, p2);
        if(p1>N && p2>N) return -1;
        p = min(p1, p2);
        if(p1<p2) s[0]++, last=0;
        else s[1]++, last=1;
    }
    if(s[0]==s[1]) return -1;
    if(s[0]>s[1] && last==1) return -1;
    if(s[0]<s[1] && last==0) return -1;
    return max(s[0], s[1]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值