D. Tennis Game(思维,模拟实现)

好难啊…

, t , s 策略很明显,枚举t,计算此时的s

为了方便,令两个人分别叫做A和B

O ( n 2 ) , 暴力计算需要O(n^2),考虑如何加速

回想一下,我们在暴力的过程中有什么可以优化的

现在已知赢一局需要 t t 分,所以第一局分出胜负的位置

要么在A赢 t t 局的位置,要么在B赢 t t 局的位置

这两个位置谁比较小就是谁赢,设这个位置在 n o w now

A B n o w 那么把A和B都提到now这个位置

n o w A x , B y 我们可以很容易得出在now这个位置A赢了x局,B赢了y局

, A x + t , B y + t 类似的,可以知道下一次分出胜负的位置是A赢x+t局,B赢y+t局位置的较小值

所以预处理A和B赢k局的位置

预处理A和B在第k个回合赢了多少局

就可以一直跳跳跳检查,思维难度不小,实现难度更大

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int f[maxn],g[maxn],n,top1,top2;
int a[maxn],b[maxn];
vector<pair<int,int> >ans;
int main()
{
	cin >> n;
	memset(f,127,sizeof(f));
	memset(g,127,sizeof(g));
	for(int i=1;i<=n;i++)
	{
		int x;
		cin >> x;
		if( x==1 )	f[++top1]=i;
		else	g[++top2]=i;
		a[i]=top1,b[i]=top2;
	}
	for(int t=1;t<=n;t++)
	{
		bool flag=1;
		int s1=0,s2=0,cur1=0,cur2=0;
		for(int cur=0;cur<=n;)//当前进行到第几局游戏 
		{
			if( cur1+t>top1&&cur2+t>top2 )//最后都不是在n点结束的 
			{
				flag=0;
				break;
			}
			int x=f[cur1+t],y=g[cur2+t];
			if( x<y )	s1++; else	s2++;
			int now=min(x,y);//进行到第now局比赛了 
			cur1=a[now],cur2=b[now];//第now局比赛时,此时1赢了cur1盘,2赢了cur2盘 
			if( now==n )
			{
				if( x<y&&s1<s2)	flag=0;//x赢最后一盘但是反而输了 
				if( x>y&&s1>s2 )	flag=0;//x赢最后一盘但是反而赢了
				if( s1==s2 )	flag=0;//平局 
				break; 
			}
			cur=now;
		}
		if( flag )	ans.push_back( make_pair(max(s1,s2),t) );
	}
	sort( ans.begin(),ans.end() );
	cout << ans.size() << endl;
	for(int i=0;i<ans.size();i++)
		printf("%d %d\n",ans[i].first,ans[i].second);
}


猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/107977251