[JZOJ5050] 颜色树

本文探讨了一个有趣的图论问题:如何在一颗特殊的树上找到所有包含所有叶子颜色的不同路径组合。通过树形DP、容斥原理及点分治等方法,解决了这一问题并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

思源湖畔有一棵树,那是独孤玉溪最喜欢的地方。
传说中,这棵不见边际的树有N个节点,每个节点都有1片叶子,每片叶子都拥有K种颜色中的一种,独孤玉溪喜欢爬到这棵树上,沿着一条路线摘叶子,并拥有所有颜色的叶子。
独孤玉溪会选择一个起点,并沿着树边走,然后最终停在一个终点上(起点和终点可能相同),当然了每一个结点只能经过一次(每一片叶子只能摘一遍)。独孤玉溪突生奇想,有多少种不同的方案能满足自己呢?(两种方案不同当且仅当起点不同或终点不同)。
20%的数据:N<=10000,K<=10
40%的数据:N<=50000,K<=2
100%的数据:N<=50000,K<=10

Solution

树形DP是非常明显的想法,需要卡一下空间。

也可以容斥,正难则反,设不存在某几种颜色的的状态,O(N)搜索联通块直接算,然后容斥。

还可以点分治,注意要把2k压成2k/2,二进制分成两半处理

Code

此处为容斥

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 50005
using namespace std;
int fs[N],nt[2*N],dt[2*N],n,cl[N],m,m1,ans;
bool bz[11],b[N];
int sqr(int x)
{
    return x*x;
}
int fd(int k)
{
    int s=1;
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(!bz[cl[p]]&&!b[p]) b[p]=1,s+=fd(p);
    }
    return s;
}
void get(int v,int l)
{
    if(l) 
    {
        memset(b,0,sizeof(b));
        fo(i,1,n) if(!b[i]&&!bz[cl[i]]) b[i]=1,ans+=v*sqr(fd(i));
    } 
    fo(i,l+1,m) bz[i]=1,get(-v,i),bz[i]=0;
}
void link(int x,int y)
{
    nt[++m1]=fs[x];
    dt[fs[x]=m1]=y;
}
int main()
{
    cin>>n>>m;
    fo(i,1,n) scanf("%d",&cl[i]);
    fo(i,1,n-1) 
    {
        int x,y;
        scanf("%d %d",&x,&y);
        link(x,y),link(y,x);
    }
    ans=0;
    get(-1,0);
    cout<<n*n-ans;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值