题解 博弈
做的挺来气的
第一步是愉快的猜题意
手模 \(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;
}