多校A层冲刺NOIP2024模拟赛03
多校A层冲刺NOIP2024模拟赛03
水题场,但是被D恶心到了
五彩斑斓
考虑计算非五彩斑斓的矩阵,就是四个角颜色全相同
枚举每对列,直接对颜色开桶就做完了,复杂度 \(O(nm^2)\)
错峰旅行
设某一时刻可选择的城市个数为 \(k_i\)
答案就是 \(\prod k_i\),因为只有一次查询,离散化之后差分做就好了,要写个快速幂
线段树
好题,原题
量子隧穿问题
发现隧道构成一个内向基环树,所以我们先考虑树的情况
我们按照边的使用顺序先后把它断掉,维护每个点有猫的概率,初始 ?
的是 \(\frac{1}{2}\),C
的是 \(1\),.
的是 \(0\)
发现断掉之后不和 \(n\) 联通的部分无意义了,更新一下和断掉的那条边相连的点的概率,方程就是
\[f_{to_i}=1-(1-f_{fr_i})(1-f_{to_i})
\]
\[f_{fr_i}=f_{fr_i}f_{to_i}
\]
等式右边的都是更新之前的值
考虑有环怎么办
这样直接断边更新概率不奏效了,因为另外一边没有完全被切掉,它仍然和 \(n\) 联通,两个点的概率相互影响,不是无关的,也就是说分布不均匀,不能直接更新
考虑直接分讨各种情况的组合,之后跑一遍树的,乘上各种情况的的概率就做完了
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
const llt N=5100;
const llt mod=1e9+7;
llt T,n,fa[N],L[N],Cans[N][2],R[N],ans[N][2],O,Ans;char s[N];bool vis;
struct UFS
{
llt F[N],Q[N];
void resize(llt n){for(int i=1;i<=n;i++) Q[i]=i,F[i]=0;}
llt find(llt now){if(!F[now]) return now;return F[now]=find(F[now]);}
void merge(llt x,llt y)
{
x=find(x),y=find(y);
if(x==y) return;
F[y]=x,Q[x]=max(Q[x],Q[y]);
}
}S;
llt qpow(llt x,llt y)
{
llt ret=1;
while(y)
{
if(y&1) ret=ret*x%mod;
x=x*x%mod;
y>>=1;
}
return ret;
}
void solve(llt i)
{
if(i>n) return;
if(L[i]==R[i]&&L[i]==-1)
{
vis=1;
for(int j=1;j<=n;j++) Cans[j][0]=ans[j][0],Cans[j][1]=ans[j][1];
ans[i][0]=1,ans[fa[i]][1]=1,ans[i][1]=0,ans[fa[i]][0]=0;
solve(i+1);Ans+=ans[n][1]*(Cans[i][0]*Cans[fa[i]][1]%mod+Cans[i][1]*Cans[fa[i]][0]%mod)%mod;
for(int j=1;j<=n;j++) ans[j][0]=Cans[j][0],ans[j][1]=Cans[j][1];
ans[i][1]=1,ans[fa[i]][1]=1,ans[i][0]=0,ans[fa[i]][0]=0;
solve(i+1);Ans+=ans[n][1]*(Cans[i][1]*Cans[fa[i]][1]%mod)%mod;
for(int j=1;j<=n;j++) ans[j][0]=Cans[j][0],ans[j][1]=Cans[j][1];
ans[i][0]=1,ans[fa[i]][0]=1,ans[i][1]=0,ans[fa[i]][1]=0;
solve(i+1);Ans+=ans[n][1]*(Cans[i][0]*Cans[fa[i]][0]%mod)%mod;
}
else if(L[i]==n)
{
ans[i][0]=(ans[i][0]*ans[fa[i]][1]%mod+ans[i][0]*ans[fa[i]][0]%mod+ans[i][1]*ans[fa[i]][0]%mod)%mod;
ans[i][1]=ans[i][1]*ans[fa[i]][1]%mod;
solve(i+1);
}
else if(R[i]==n)
{
ans[fa[i]][1]=(ans[i][1]*ans[fa[i]][1]%mod+ans[i][0]*ans[fa[i]][1]%mod+ans[i][1]*ans[fa[i]][0]%mod)%mod;
ans[fa[i]][0]=ans[i][0]*ans[fa[i]][0]%mod;
solve(i+1);
}
else solve(i+1);
}
int main()
{
freopen("experiment.in","r",stdin);
freopen("experiment.out","w",stdout);
scanf("%lld",&T);
while(T--)
{
scanf("%lld",&n);scanf("%s",s+1);Ans=O=0;S.resize(n);
for(int i=1;i<=n;i++) scanf("%lld",&fa[i]);
for(int i=1;i<=n;i++)
if(s[i]=='.') ans[i][0]=1,ans[i][1]=0;
else if(s[i]=='C') ans[i][0]=0,ans[i][1]=1;
else if(s[i]=='?') ans[i][0]=ans[i][1]=qpow(2,mod-2),O++;
for(int i=n;i>=1;i--)
{
if(S.find(i)==S.find(fa[i])&&S.Q[S.find(i)]==n) L[i]=R[i]=-1;
else L[i]=S.Q[S.find(i)],R[i]=S.Q[S.find(fa[i])];
S.merge(i,fa[i]);
}
solve(1);if(!vis)Ans=ans[n][1];vis=0;
printf("%lld\n",Ans*qpow(2,O)%mod);
}
return 0;
}