题意:两个人进行比赛,分为大分s和小分t。已知他们比赛每局的胜负情况,问有多少种s和t的情况。
思路:枚举小分t判断是否合法,并且求出大分s。两人大分不能相同,和分数大的人必须是最后一大局的胜者。枚举的时候,通过二分来优化。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int n,val[100010],num1[100010],num2[100010],num,win,last,win1,win2;
struct node
{
int a,b;
}ans[100010];
bool cmp(node a, node b)
{
if(a.a==b.a)
return a.b<b.b;
return a.a<b.a;
}
int find(int a,int t)
{
int l=a+1,r=n,mi;
while(l<r)
{
mi=(l+r)/2;
if(max(num1[mi]-num1[a],num2[mi]-num2[a])>=t)
r=mi;
else
l=mi+1;
}
if(max(num1[l]-num1[a],num2[l]-num2[a])>=t)
{
if(num1[l]-num1[a]==t)
win=1;
else
win=2;
return l;
}
else
return -1;
}
int main()
{
int T,t,m,i,j,k,a,b,numa,numb,q;
bool flag;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&k);
num1[i]=num1[i-1];num2[i]=num2[i-1];
if(k==1)
num1[i]++;
else
num2[i]++;
}
for(t=1;t<=n;t++)
{
a=0;b=0;win1=0;win2=0;
flag=true;
while(a<n)
{
k=find(a,t);
if(k==-1)
{
flag=false;
break;
}
a=k;
if(win==1)
win1++;
else
win2++;
}
if(flag)
{
if(win1==win2)
flag=false;
if(win1>win2 && win==2)
flag=false;
if(win2>win1 && win==1)
flag=false;
}
if(flag)
{
num++;
ans[num].a=max(win1,win2);
ans[num].b=t;
}
}
printf("%d\n",num);
if(num>0)
{
sort(ans+1,ans+1+num,cmp);
for(i=1;i<=num;i++)
printf("%d %d\n",ans[i].a,ans[i].b);
}
}