CF1860C 题解

显然是一个博弈论题,考虑 dp。

定义状态 \(dp_i\) 表示先手走到 \(i\) 之后是否有必胜策略,不难发现以下几点:

  1. 若走到 \(i\) 之后无路可走,那么就必败。

  2. 若走到 \(i\) 之后对手只能走到一个必败点那么这就是必胜点。

  3. 除开以上两种情况都是必败点。

\(1\) 表示必胜,\(0\) 表示必败,所有操作就是对 dp 数组的单点修改和前缀最大值。

考虑用树状数组维护即可。

#include<bits/stdc++.h>
//#define int long long
#define lowbit(x) (x&-(x))
using namespace std;
const int maxn = 3e5+114;
const int top = 3e5;
int dp[maxn],tr[maxn];
void add(int x,int v){
	while(x<=top) tr[x]=max(tr[x],v),x+=lowbit(x);
}
int pre(int x){
	int res=0;
	while(x>0) res=max(res,tr[x]),x-=lowbit(x);
	return res;
}
int n,p[maxn],T;
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--){
memset(dp,0,sizeof(dp));
memset(p,0,sizeof(p));
for(int i=1;i<maxn;i++) tr[i]=0;
cin>>n;
int mi=100000007;
for(int i=1;i<=n;i++){
	cin>>p[i];
	if(pre(p[i])==0&&p[i]>mi) dp[i]=1;
	else dp[i]=0;
	add(p[i],dp[i]);
	mi=min(mi,p[i]);
}
int ans=0;
for(int i=1;i<=n;i++){
	if(dp[i]==1){
		ans++;
	}
}	
cout<<ans<<'\n';
}

return 0;
}
posted @ 2024-01-30 23:52  ChiFAN鸭  阅读(5)  评论(0编辑  收藏  举报