多校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;
}
posted @ 2024-10-08 17:15  wang54321  阅读(30)  评论(4编辑  收藏  举报