好难啊…
策 略 很 明 显 , 枚 举 t , 计 算 此 时 的 s 策略很明显,枚举t,计算此时的s 策略很明显,枚举t,计算此时的s
为了方便,令两个人分别叫做A和B
暴 力 计 算 需 要 O ( n 2 ) , 考 虑 如 何 加 速 暴力计算需要O(n^2),考虑如何加速 暴力计算需要O(n2),考虑如何加速
回想一下,我们在暴力的过程中有什么可以优化的
现在已知赢一局需要 t t t分,所以第一局分出胜负的位置
要么在A赢 t t t局的位置,要么在B赢 t t t局的位置
这两个位置谁比较小就是谁赢,设这个位置在 n o w now now
那 么 把 A 和 B 都 提 到 n o w 这 个 位 置 那么把A和B都提到now这个位置 那么把A和B都提到now这个位置
我 们 可 以 很 容 易 得 出 在 n o w 这 个 位 置 A 赢 了 x 局 , B 赢 了 y 局 我们可以很容易得出在now这个位置A赢了x局,B赢了y局 我们可以很容易得出在now这个位置A赢了x局,B赢了y局
类 似 的 , 可 以 知 道 下 一 次 分 出 胜 负 的 位 置 是 A 赢 x + t 局 , B 赢 y + t 局 位 置 的 较 小 值 类似的,可以知道下一次分出胜负的位置是A赢x+t局,B赢y+t局位置的较小值 类似的,可以知道下一次分出胜负的位置是A赢x+t局,B赢y+t局位置的较小值
所以预处理A和B赢k局的位置
预处理A和B在第k个回合赢了多少局
就可以一直跳跳跳检查,思维难度不小,实现难度更大
#include
using namespace std;
const int maxn=2e5+10;
int f[maxn],g[maxn],n,top1,top2;
int a[maxn],b[maxn];
vector >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( xy&&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