牛客周赛139 E,F题

E 小红的树权值

知识点:树形dp

image

思路:注意到,对于任意一个节点来说,如果不删除它本身,就需要删除他的儿子和父亲,反之则可以选择不删除。这样这个题就很像没有上司的舞会,属于树形dp入门题目。

Code
点击查看代码
vi adj[M];
vvi dp;
void dfs(int now,int fa)
{
    for(int i:adj[now])
    {
        if(i==fa)
        {
            continue;
        }
        dfs(i,now);
        dp[now][0]+=dp[i][1];//如果不删这个点,就一定要删儿子节点
        dp[now][1]+=min(dp[i][0],dp[i][1]);//如果删除这个点,那么儿子节点删不删无所谓,取 min 值
    }
}
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        adj[i].clear();
    }
    dp.assign(n+1,vi(2,0));//二维dp,dp[i][1]表示删除 i 点,dp[i][0]表示不删除
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        adj[u].push_back(v);
        adj[v].push_back(u);//存边
    }
    for(int i=1;i<=n;i++)
    {
        dp[i][1]=1;//对dp数组进行初始化,如果删除,贡献为 1
        dp[i][0]=0;//不删除贡献为 0
    }
    dfs(1,-1);//对根节点进行dfs
    for(int i=1;i<=n;i++)
    {
        cout<<min(dp[i][0],dp[i][1])<<' ';
    }
    cout<<endl;
}

F 小红的部分不同字符串

知识点:基环树的性质,拓扑排序,并查集

思路:对 \(i\)\(a_{i}\) 连边,意思就是凡是一条边上的两点颜色不能相同 。
\(n\) 条边和 \(n\) 个点,构成一个基环树森林,因为树是 \(n\) 个点和 \(n-1\) 条边,如果多出一条边一定会构成环,且环有且仅有一个。
重点 1:对于两棵基环树,其染色方案数应互不干扰,满足乘法原理
重点 2:对于一棵基环树除环之外的其他点,其可以选择的方案数都是 \(25\)
重点 3:基环树上染色结论,设颜色总数为 \(m\) 种,设基环树上环的长度为 \(len\)
对这个环进行染色,总方案数为 \((m-1)^{len}+(-1)^{len}*(m-1)\) 种 ,将环上方案数与链上方案数相乘即为基环树染色方案数

Code

点击查看代码
void solve()
{
    cin>>n;
    init();
    vi a(n+1);
    vi ind(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        join(i,a[i]);
        ind[a[i]]++;
    }
    vi vis(n+1);
    queue<int>p;
    for(int i=1;i<=n;i++)
    {
        if(ind[i]==0)
        {
            p.push(i);
        }
    }
    while(p.size())
    {
        auto t=p.front();
        p.pop();
        vis[t]=1;
        ind[a[t]]--;
        if(ind[a[t]]==0)
        {
            p.push(a[t]);
        }
    }
    vi len(n+1);
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            len[find(i)]++;
        }
    }
    int ans=1;
    for(int i=1;i<=n;i++)
    {
        if(fa[i]!=i)continue;
        int now=ksm(25,sz[find(i)]-len[find(i)],mod)*(ksm(25,len[find(i)],mod)+25*ksm(-1,len[i],mod)%mod)%mod;
        ans=ans*now%mod;
    }
    cout<<ans<<endl;
}

代码:对基环树进行拓扑排序,如果一个点在环上,那么它永远不可能入队,所以在拓扑的过程中标记一下,没入队的就是在环上的。计算出环的长度,用公式和乘法原理即可。

公式证明

考虑环染色本身是不大可做的,所以我们考虑从链去推。

假设有一条 \(n\) 个结点的链,有 \(q\) 种颜色。

\(S_n\) 为这条链的染色方案数。

考虑分两种情况讨论:

  1. 首尾不同,方案数记作 \(A_n\),此时首尾相连可直接成环,是我们要求的东西;

  2. 首尾相同,方案数记作 \(B_n\),由结点 \(1\) 与结点 \(n\) 颜色相同,结点 \(n-1\) 与 结点 \(n\) 颜色不同。

    可得,结点 \(1\) 和结点 \(n-1\) 颜色不同。

    故若去掉最后一个结点 \(n\),那么此时恰好可以成为一个 \(n-1\) 个结点的环。

可得

\[\begin{array}{rl} S_n & = A_n + B_n \\ & = A_n + A_{n - 1}\\ & = q \cdot (q - 1)^{n - 1} \end{array} \]

考虑特例。

考虑 \(A_2\) 即为 \(S_2\),所以 \(S_2=A_2=q(q-1)\)

\(S_3=A_3+A_2=q(q-1)^2\)

那么:

\(A_3=S_3-A_2=q(q-1)^2-q(q-1)\)

\(A_4=S_4-A_3=q(q-1)^3-q(q-1)^2+q(q-1)\)

注意到,\(A_n\) 为等比数列求和。

\(n\) 为奇数时,

\[\begin{array}{rl} A_n & = -q\cdot(q-1)\cdot\dfrac{1-(1-q)^{n-1}}{1-(1-q)}\\ & =(q-1)^n-(q-1) \end{array} \]

\(n\) 为偶数时,

\[\begin{array}{rl} A_n & = q\cdot(q-1)\cdot\dfrac{1-(1-q)^{n-1}}{1-(1-q)}\\ & =(q-1)^n+(q-1) \end{array}\]

posted @ 2026-04-13 17:18  Lambda_L  阅读(8)  评论(0)    收藏  举报