USACO17DEC Barn Painting

给你一颗大小为n<=1e5的树,三种颜色,每个点涂一种颜色,相邻点不能同色。下面告诉你一些点已经被涂色,并
且告诉你是哪一种颜色,问你涂完整棵树有多少种方法?mod 1e9+7。

考虑树上dp,设(f_{u,i})表示以u为根的子树中,u被染成i这个颜色的方案数,于是考虑状态转移方程

如果这个点被指定染色了,那么有

[f_{u,c_u}=prod_{vin son(u)}sum_{i=1}^3 f_{v,i} (i e c_u) ]

因为假如u选了一个颜色,那么它的每个儿子都只能有两种颜色可选,先用加法原理统计儿子可选的颜色,然后再用乘法原理统计这棵子树的答案

然后可以得出未被指定颜色点的方程

[egin{cases}f_{u,1}=prod_{vin son(u)} (f_{v,2}+f_{v,3})\f_{u,2}=prod_{vin son(u)} (f_{v,1}+f_{v,3})\f_{u,3}=prod_{vin son(u)} (f_{v,1}+f_{v,2}) end{cases}]

这样就做完了QAQ

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
const int N = 1e5;
const int p = 1e9 + 7;
using namespace std;
int n,k,c[N + 5],f[N + 5][4];
vector <int> d[N + 5];
void dfs(int u,int fa)
{
    vector <int>::iterator it;
    int sum[4] = {1,1,1,1};
    for (it = d[u].begin();it != d[u].end();it++)
    {
        int v = (*it);
        if (v == fa)
            continue;
        dfs(v,u);
        if (c[u])
        {
            int s = 0;
            for (int i = 1;i <= 3;i++)
                if (i != c[u])  
                    s = (s + f[v][i]) % p;
            sum[c[u]] = 1ll * sum[c[u]] * s % p;
        }
        else
            for (int i = 1;i <= 3;i++)
            {
                int s = 0;
                for (int j = 1;j <= 3;j++)
                    if (i != j)
                        s = (s + f[v][j]) % p;
                sum[i] = 1ll * sum[i] * s % p;
            }
    }
    if (c[u])
        f[u][c[u]] = sum[c[u]];
    else
        for (int i = 1;i <= 3;i++)
            f[u][i] = sum[i];
}
int main()
{
    scanf("%d%d",&n,&k);
    int u,v;
    for (int i = 1;i < n;i++)
    {
        scanf("%d%d",&u,&v);
        d[u].push_back(v);
        d[v].push_back(u);
    }
    for (int i = 1;i <= k;i++)
    {
        scanf("%d%d",&u,&v);
        c[u] = v;
    }
    dfs(1,0);
    cout<<((f[1][1] + f[1][2]) % p + f[1][3]) % p<<endl;  
    return 0;
}
原文地址:https://www.cnblogs.com/sdlang/p/13068297.html