[每日随题13] 博弈论 - 二分 - 拓扑排序

整体概述

  • 难度:1000 \(\rightarrow\) 1400 \(\rightarrow\) 1500

P1288 取数游戏 II

  • 标签:博弈论

  • 前置知识:无

  • 难度:橙 1000

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

4
2 5 3 0
3
0 0 0

样例输出:

YES
NO

解题思路:

  • 我们发现,如果先手距离某个 \(0\) 的距离为奇数,那么他只需要一路向该 \(0\) 狂奔,每次取成 \(0\) 即可获胜。

  • 而如果距离均为偶数,那么无论先手如何取数,对于后手而言,其均进入了必胜态。

  • 那么我们只需要考虑先手是否与某个 \(0\) 的距离为奇数即可。

完整代码

#include<bits/stdc++.h>
#define Size(x) ((int)(x).size())
#define int long long
using namespace std;
const int N = 25;
int n,a[N];
inline string solve(){
	cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i];
	for(int i=1;i<=n;i++){
		if(!a[i] && (i-1)&1) return "YES";
		if(!a[i]) break;
	}
	for(int i=n;i>=1;i--){
		if(!a[i] && (n-i)&1) return "YES";
		if(!a[i]) break;
	}
	return "NO";
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cout << solve();
	return 0;
}

P4343 [SHOI2015] 自动刷题机

  • 标签:二分

  • 前置知识:无

  • 难度:黄 1400

题目描述:

image

输入格式:

image

image

输出格式:

image

样例输入:

4 2
2
5
-3
9

样例输出:

3 7

解题思路:

  • 我们发现对于一个给定的序列,\(n\) 越大能够通过的题数越少,具有单调性,可以对最后的 \(n\) 进行二分。

  • 分别记录满足 \(\le k\) 中,等于 \(k\) 的最大值,以及 \(\ge k\) 中,等于 \(k\) 的最小值即可。

完整代码

#include<bits/stdc++.h>
#define mid (((l)+(r))>>1)
#define int long long
using namespace std;
const int N = 1e5+5;
int n,k,a[N];
inline int get(int val){
	int cnt = 0;
	for(int i=1,sum=0;i<=n;i++){
		sum = max(0ll,sum+a[i]);
		if(sum >= val) sum = 0,++cnt;
	}
	return cnt;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n >> k;
	for(int i=1;i<=n;i++) cin >> a[i];
	int l = 1,r = 1e18,ans1 = -1,ans2 = -1;
	while(l<=r){
		int cur = get(mid);
		if(cur <= k){
			if(cur == k) ans1 = mid;
			r = mid-1;	
		}else l = mid+1;
	}
	l = 1,r = 1e18;
	while(l<=r){
		int cur = get(mid);
		if(cur >= k){
			if(cur == k) ans2 = mid;
			l = mid+1;
		}else r = mid-1;
	}
	if(ans1 == -1) cout << -1;
	else cout << ans1 << ' ' << ans2;
	return 0;
}


P4089 [USACO17DEC] The Bovine Shuffle S

  • 标签:拓扑排序

  • 前置知识:链式前向星

  • 难度:黄 1500

题目描述:

image

输入格式:

image

输出格式:

image

样例输入:

4
3 2 1 3

样例输出:

3

解题思路:

  • 我们发现,想要无论什么时候都有奶牛,那么必须这些奶牛在环上。

  • 所以问题就转化为求有多少个奶牛在环上,我们可以拓扑排序一下,将所有非环上的点的入度减到 \(0\),最后统计有多少个奶牛的入度非 \(0\) 即可。

完整代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n,ha[N],idx,in[N],a[N];
struct Edge{int to,ne;}edge[N];
inline void ins(int u,int v){
	edge[++idx] = {v,ha[u]}, ha[u] = idx;
	in[v] += 1;
}
queue<int> qu; bool vis[N];
inline void topu(){
	for(int i=1;i<=n;i++) if(!in[i]) qu.push(i),vis[i] = true;
	while(!qu.empty()){
		int u = qu.front(); qu.pop();
		for(int i=ha[u];i;i=edge[i].ne){
			int v = edge[i].to;
			if(!vis[v] && !--in[v]) qu.push(v),vis[v] = true;
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n;
	for(int i=1;i<=n;i++) cin >> a[i],ins(i,a[i]);
	topu();
	int res = 0;
	for(int i=1;i<=n;i++) if(in[i]) res++;
	cout << res;
	return 0;
}

posted @ 2025-07-20 10:24  浅叶梦缘  阅读(6)  评论(0)    收藏  举报