题解 博弈

传送门

做的挺来气的

第一步是愉快的猜题意
手模 \(2^5=32\) 种情况之后可以发现两个棋子可以在同一个节点上
那么这样的话所有棋子之间是独立的
但是怎么合并所有棋子之间的贡献呢?
因为只考虑一个棋子的话,后出现连续段的人必死
但若有多个棋子的话这个棋子可能在之后继续产生影响
那么“所以两个人的策略都是最大化自己能走的步数减去对方能走的步数”
这样就可以统计贡献了

  • 对于各棋子或什么东西相互独立,但不完全独立(影响到游戏什么时候结束)的情况考虑量化一个棋子的贡献?

这个步数是容易 DP 的,初值为 0
根据这个点的颜色看是后继最大/小值即可
那么剩下的事情就是对这些 DP 值做一个背包了
复杂度 \(O(n^3)\),瓶颈在于背包

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define int long long

int n, m;
char col[N];
vector<int> e[N], re[N];
const ll mod=998244353;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}

namespace force{
	int ans;
	const ull base=13131;
	map<ull, bool> mp[2];
	bool dfs(char now, vector<int> s) {
		ull h=0;
		for (auto& it:s) h=h*base+it;
		if (mp[now].find(h)!=mp[now].end()) return mp[now][h];
		bool any_lose=0;
		for (int i=0; i<n&&!any_lose; ++i) if (now==col[i]&&s[i]) {
			for (auto& v:e[i]) {
				--s[i]; ++s[v];
				if (!dfs(now^1, s)) any_lose=1;
				++s[i]; --s[v];
			}
		}
		return mp[now][h]=any_lose;
	}
	void solve() {
		int lim=1<<n;
		for (int s=0; s<lim; ++s) {
			vector<int> tem; tem.resize(n);
			for (int i=0; i<n; ++i) tem[i]=(s&(1<<i))?1:0;
			if (dfs(0, tem)) ++ans;
		}
		cout<<ans<<endl;
	}
}

namespace task{
	queue<int> q;
	ll f[2][N], ans;
	int cnt[N], dp[N], now;
	#define f(a, b) f[a][b+100000]
	void solve() {
		for (int i=1; i<=n; ++i) for (auto v:e[i]) re[v].pb(i), ++cnt[i];
		for (int i=1; i<=n; ++i) if (!cnt[i]) q.push(i);
		while (q.size()) {
			int u=q.front(); q.pop();
			dp[u]=0;
			for (auto v:e[u])
				if (col[u]) dp[u]=min(dp[u], dp[v]-1);
				else dp[u]=max(dp[u], dp[v]+1);
			for (auto v:re[u]) if (--cnt[v]==0) q.push(v);
		}
		f(now, 0)=1;
		for (int i=1; i<=n; ++i,now^=1) {
			memset(f[now^1], 0, sizeof(f[now^1]));
			for (int j=-n*n; j<=n*n; ++j) {
				md(f(now^1, j), f(now, j));
				if (j+dp[i]>=-n*n && j+dp[i]<=n*n) md(f(now^1, j+dp[i]), f(now, j));
			}
		}
		for (int i=1; i<=n*n; ++i) md(ans, f(now, i));
		cout<<ans<<endl;
	}
}

signed main()
{
	freopen("game.in", "r", stdin);
	freopen("game.out", "w", stdout);

	scanf("%d%d%s", &n, &m, col+1);
	for (int i=1; i<=n; ++i) col[i]=col[i]=='B'?1:0;
	for (int i=1,u,v; i<=m; ++i) scanf("%d%d", &u, &v), e[u].pb(v);
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2022-03-27 20:56  Administrator-09  阅读(3)  评论(0编辑  收藏  举报