题解:P13004 [GCJ 2022 Finals] Schrödinger and Pavlov
题意
有
C:有一只猫。.:没有猫。?:可能有猫,有猫和没有猫的概率相同。
每个盒子
现在,从
-
如果盒子
i 里没有猫 或 盒子b[i] 里有猫,不执行操作。 -
否则,盒子
i 中的猫移动到盒子b[i] 中。
求盒子
分析
方案数不好算,我们可以转为算概率,最终方案数就是:盒子 ? 的个数次幂”。
可以转为图论模型:每个点
那么一共有
一般基环树的题目都是从树上问题开始,最后特殊讨论环上情况,我们这里也使用这种思路。
如果没有环,也就意味着 无后效性。
那么我们可以从
设盒子里有猫的概率为
那么初值有:
对于转移,分类讨论即可。对于
注意转移前先用两个变量存一下
接下来看环。
发现对于环上编号最小的点
此时断开
:::info[为什么断开
因为
这样就容易理解为什么不能断开其他边,因为都会使得
理解了这点,这题就不难了。 :::
#include <bits/stdc++.h>
using namespace std;
#define intt long long
const intt mod = 1000000007;
const intt inv2 = 500000004;
const int N = 5005;
int t,n,b[N],c;
intt a[N],ans,fu,fv,res,w;
char s[N];
bool vis[N];
stack<int> st;
void dfs(int u)
{
if (vis[u])
{
c = u;
while (st.size())
{
int v = st.top();
c = min(c,v);
if (v == u) break;
st.pop();
}
while (st.size()) st.pop();
return;
}
vis[u] = 1;
st.push(u);
dfs(b[u]);
}
int main()
{
scanf("%d",&t);
for (int T=1;T<=t;T++)
{
scanf("%d",&n);
scanf("%s",s+1);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
memset(vis,0,sizeof(vis));
res = 1; ans = 0;
dfs(n);
// cout << "c: " << c << endl;
for (int p1=0;p1<=1;p1++)
{
for (int p2=0;p2<=1;p2++)
{
w = 1;
for (int i=1;i<=n;i++)
{
if (s[i] == '.') a[i] = 0;
else if (s[i] == 'C') a[i] = 1;
else a[i] = inv2;
}
for (int i=1;i<=n;i++)
{
if (i == c)
{
if (p1 == 0) a[c] = (1-a[c]+mod)%mod;
if (p2 == 0) a[b[c]] = (1-a[b[c]]+mod)%mod;
w = a[c] * a[b[c]] % mod;
a[c] = p1; a[b[c]] = p2;
}
fu = a[i]; fv = a[b[i]];
a[i] = fu * fv % mod;
a[b[i]] = ((fv + fu - fu * fv % mod) % mod + mod) % mod;
}
ans = (ans + w*a[n] % mod) % mod;
}
}
for (int i=1;i<=n;i++)
{
if (s[i] == '?') res = res * 2 % mod;
}
res = res * ans % mod;
printf("Case #%d: %lld",T,res);
puts("");
}
return 0;
}