B-杰哥的树(状压树形dp)

链接:杰哥的树

题意:

给定一棵树,边权 是 {a,b,c,d,e,f} 这六个字符,求不同的路径数,要求路径上的字符都恰好出现偶数次。

做法:

只关心奇偶,那么一个字符就可有两个状态——1代表奇数个,0代表偶数个,要想同时表示六个字符是奇数还是偶数,就可用0~63来表示。

定义 f[x][i] 为以第 x 个节点为起点,状态为 i 有多少路径数量,如果 x 的儿子是 y ,当前字符是 ch ,那么 f\;[\;x\;][\;i\;]\; += f[\;y\;][\;i \oplus (1 << (ch - 'a'))\;],除了由儿子的状态转移而来,还会有新的状态,不继承儿子的状态,xy 的这条边也可单独作为一个状态,则当i == (1<<(ch - 'a'))时, f\;[\;x\;][\;i\;]++

还要考虑点x作为中间节点的情况,这个简单,由f[x][i] 计算即可。

代码:

struct tree
{
    int y, val;
};
vector<tree> v[N];
int f[N][1ll << 6];
int ans;
void dfs(int x, int fa)
{
    f[x][0] = 0;
    for (auto tt : v[x])
    {
        int y = tt.y, val = tt.val;
        if (y == fa) continue;
        dfs(y, x);
        for (int i = 0; i < (1ll << 6); i++)
        {
            f[x][i] += f[y][i ^ (1ll << val)];
            if (i == (1ll << val)) f[x][i]++;   //不能乱加1,之所以加1,是因为定义x这个点只出一条边
        }
    }
    ans += f[x][0];
    int sum = 0;
    for (auto tt : v[x])
    {
        int y = tt.y, val = tt.val;
        if (y == fa) continue;
        for (int i = 0; i < (1ll << 6); i++)
        {
            int x1 = f[x][i] - f[y][i ^ (1ll << val)] - (i == (1ll << val));
            int x2 = f[y][i ^ (1ll << val)] + (i == (1ll << val));
            sum += x1 * x2;
        }
    }
    ans += sum / 2;
}
void solve()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n - 1; i++)
    {
        int x, y;
        char c;
        scanf("%lld%lld", &x, &y);
        cin >> c;
        v[x].emplace_back(tree{y, c - 'a'});
        v[y].emplace_back(tree{x, c - 'a'});
    }
    dfs(1, 0);
    cout << ans << "\n";
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值