乒乓球

这里写图片描述
这里写图片描述
刚开始想用两侧循环来枚举S,T,请仔细一想没有必要,因为T确定了,S也就确定了
于是使用1层循环枚举T,这样我们看赢的多的人的局数,即为S
注意以下四种情况
1:没有人赢(无解)
2:两个人赢的一样多(无解)
3:赢的多的人却输了最后一局(因为先拿到大局数的人胜,显然最后一局是多的人赢的)
4:没有用完所有对局数大局就结束了(无解)
这样我们进行枚举,复杂度N^2,这是70的数据
其实我们不需要枚举,计算某个人谁先拿到T分(也就是赢下小局)时使用二分+前缀和的办法,看誰拿到T分的位置靠前(可以使用lower_bound实现,不会百度!)
复杂度:N*logN
可以AC

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int sum1[199999],sum2[199999];
int cnt,n;
struct tw{
    int s;
    int t;
};
tw ans[99999];
inline void work(int t)
{
    int s1=0;
    int s2=0;

    int s1_win=0;
    int s2_win=0;

    int last_win=0;
    int w=0;
    while(1)
    {
      int w1=lower_bound(sum1+w,sum1+n+1,s1+t)-sum1;
      int w2=lower_bound(sum2+w,sum2+n+1,s2+t)-sum2;

      if(w1>n&&w2>n) break;
      if(w1<w2) s1_win++,last_win=1;
      else      s2_win++,last_win=2;

      w=min(w1,w2);
      s1=sum1[w];
      if(w1>n) s1=1e7; 
      s2=sum2[w];
      if(w2>n) s2=1e7;
    }
    if(w!=n) return;
    if(s1_win==s2_win) return;
    if(s1_win>s2_win&&last_win==2) return;
    if(s1_win<s2_win&&last_win==1) return;

    int win=max(s1_win,s2_win);

    ans[++cnt].s=win,ans[cnt].t=t;
} 
bool comp(const tw&a,const tw&b)
{
    if(a.s<b.s) return 1;
    if(a.s>b.s) return 0;
    return a.t<b.t;
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d",&n);

    for(int i=1,a;i<=n;i++)
    {
        scanf("%d",&a);
        sum1[i]=sum1[i-1];
        sum2[i]=sum2[i-1];
        if(a==1) sum1[i]++;
        else     sum2[i]++;
    }

    for(int i=1;i<=n;i++)
      work(i); 

    sort(ans+1,ans+cnt+1,comp); 

    if(!cnt) printf("0");
    else
    {
        printf("%d\n",cnt);
        for(int i=1;i<=cnt;i++)
         printf("%d %d\n",ans[i].s,ans[i].t);
    }

    return 0;
}

重改后代码。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
struct node{
    int s,t;
}a[110000];
int cnt;
bool comp(node x,node y)
{
    if(x.s==y.s) return x.t<y.t;
    return x.s<y.s; 
}
int n;
int cnt1[110000],cnt2[110000];
void check(int t)
{
    int nows1=0,nows2=0,flag=0;
    int last_win=0;
    int nowwin1=t,nowwin2=t;
    while(1)
    {
        int s1=lower_bound(cnt1+1,cnt1+n+1,nowwin1)-cnt1;
        int s2=lower_bound(cnt2+1,cnt2+n+1,nowwin2)-cnt2;
        if(s1>n&&s2>n) break;
        if(s1<s2) 
        {
            nows1++,last_win=1,nowwin1=cnt1[s1]+t,nowwin2=cnt2[s1]+t;
            if(s1==n) flag=1;
        }
        else 
        {
            nows2++,last_win=2,nowwin1=cnt1[s2]+t,nowwin2=cnt2[s2]+t;
            if(s2==n) flag=1;
        }
    }
    if(flag&&nows1>nows2&&last_win==1) a[++cnt]=((node){nows1,t});
    if(flag&&nows1<nows2&&last_win==2) a[++cnt]=((node){nows2,t});
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d",&n);

    for(int i=1,x;i<=n;i++)
    {
        scanf("%d",&x);
        if(x==1)
         cnt1[i]=cnt1[i-1]+1,cnt2[i]=cnt2[i-1];
        else cnt1[i]=cnt1[i-1],cnt2[i]=cnt2[i-1]+1;
    }

    for(int i=1;i<=n;i++)
     check(i);

    sort(a+1,a+cnt+1,comp);
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)
     printf("%d %d\n",a[i].s,a[i].t);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值