Codeforces Gym102448J Jingle Bells

3 篇文章 0 订阅
1 篇文章 0 订阅

题目链接

Codeforces Gym102448J Jingle Bells

题目大意

给定一棵有 n n n个节点的树,树的边一共有 5 5 5种颜色,刚开始树的有些边已经被染色了。现在要你把剩下没染色的边染色,让两条具有公共节点的相邻的边的颜色不同,有多少种方案,对 1 0 9 + 7 10^9+7 109+7取模。

解题思路

树形 d p dp dp,可以看出这题要在树上计数, d p dp dp

发现树的边一共有 5 5 5种颜色,非常少,那么我们可以状压。 我们先转化一下,将“两条相邻的边的颜色不同”转化成“任意一个点连出的边的颜色都不相同”。于是我们设 f x , s t a f_{x,sta} fx,sta表示以 x x x为子树的根,从 x x x连出的边的颜色状态为 s t a sta sta时,染色的方案数。

然后我们考虑状态转移方程。设 s o n x son_x sonx x x x的子节点集合, y y y x x x的当前计算的子节点, p o s pos pos y y y节点的边染色状态,当前新加的边颜色为 c o l o r color color,则
f x , s t a ∣ 2 c o l o r = ∑ y ∈ s o n x f x , s t a × f y , p o s ( p o s & 2 c o l o r = 0 ) f_{x,sta\mid 2^{color}}=\sum_{y\in son_x} f_{x,sta}\times f_{y,pos(pos\&2^{color}=0)} fx,sta2color=ysonxfx,sta×fy,pos(pos&2color=0)
表示为新推出的状态由现在状态的方案数乘子节点不包含新增边颜色的所有状态的方案数。

注意点

树形 d p dp dp顺序

从大到小,因为从小到大会重复计算。在 s t a sta sta状态的时候,往 s t a ∣ 2 c o l o r sta\mid 2^{color} sta2color状态加入了方案数,而 s t a ∣ 2 c o l o r > s t a sta\mid2^{color}>sta sta2color>sta,所以往后转移的时候方案数会重复叠加产生错误。

清零

在用 f x , s t a f_{x,sta} fx,sta转移 f x , s t a ∣ 2 c o l o r f_{x,sta|2^{color}} fx,sta2color后,将 f x , s t a f_{x,sta} fx,sta赋值为 0 0 0。 这是为什么呢? 因为 x x x可能有多个子节点 y y y,由 f x , s t a f_{x,sta} fx,sta f y , p o s f_{y,pos} fy,pos转移后, f x , s t a ∣ 2 c o l o r f_{x,sta|2^{color}} fx,sta2color就被更新了,此时的 f x , s t a f_{x,sta} fx,sta不能继续使用,因为枚举顺序是从大到小,导致了此时使用的 f x , s t a f_{x,sta} fx,sta实际上是上一个子节点 y 1 y_1 y1留下的方案数,和 01 01 01背包的从大到小的思想类似,相当于把 f x , s t a f_{x,sta} fx,sta里的每种方案数都 × f y , p o s \times f_{y,pos} ×fy,pos,乘法原理。上一步是 y 1 y_1 y1子节点及之前的答案,这一步新增了 y y y节点,那么就是 y y y节点的方案 × y 1 \times y_1 ×y1节点及之前的所有方案。

更好理解的方法,假设节点 x x x 3 3 3个子节点 y 1 , y 2 , y 3 y_1,y_2,y_3 y1,y2,y3,我们已经出来出 y 1 y_1 y1更新的方案数了,这时假设我们还不知道有 y 2 , y 3 y_2,y_3 y2,y3,新开辟了一个 y 2 y_2 y2节点,那么我们原来的方案数就要乘 y 2 y2 y2 x x x这条边的染色方案数,然后原来的方案数是没 y 2 y_2 y2的时候的,用完后清零,再由 f x , s t a 1 ( s t a 1 ∈ s t a ) f_{x,sta_1(sta_1\in sta)} fx,sta1(sta1sta)后面状态的方案数去更新本次新增节点 y 2 y_2 y2后的方案数。

代码实现

#include<bits/stdc++.h>
#define For(i,a,b)for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=1e9+7,up=31;
ll f[N][32],ans;
int n,cnt,x,y,z,a[N],b[N],c[N],d[N];
void add(int x,int y,int z){a[++cnt]=y,b[cnt]=c[x],c[x]=cnt,d[cnt]=z;}
void dfs(int x,int fa){
    f[x][0]=1;//什么颜色都不染方案数为1
    for(int i=c[x];i;i=b[i])if(a[i]!=fa){
        dfs(a[i],x);
        int y=a[i],l=0,r=4;//五种颜色
        if(d[i])l=r=d[i]-1;//假如这条边本身有色就设为自己
        for(int sta=up;sta>=0;f[x][sta--]=0)//倒序枚举状态
            for(int c=l;c<=r;c++)if(!(f[x][sta]==0||(sta&(1<<c))))//这条边颜色
                for(int son=0;son<=up;son++)if(!(son&(1<<c)))//子节点状态
                    f[x][sta|(1<<c)]=(f[x][sta|(1<<c)]+f[x][sta]*f[y][son]%mod)%mod;//增加方案
    }
}
int main(){
    scanf("%d",&n);
    For(i,2,n)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
    dfs(1,0);For(i,0,up)(ans+=f[1][i])%=mod;//f[1]中为答案每种状态都行,无限制
    return printf("%lld\n",ans),0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您提供的链接是Codeforces的一个问题,问题编号为104377。Codeforces是一个知名的在线编程竞赛平台,经常举办各种编程比赛和训练。Gym是Codeforces的一个扩展包,用于组织私人比赛和训练。您提供的链接指向了一个问题的页面,但具体的问题内容和描述无法通过链接获取。如果您有具体的问题或需要了解关于Codeforces Gym的更多信息,请提供更详细的信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [http://codeforces.com/gym/100623/attachments E题](https://blog.csdn.net/weixin_30820077/article/details/99723867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [http://codeforces.com/gym/100623/attachments H题](https://blog.csdn.net/weixin_38166726/article/details/99723856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [CodeforcesPP:Codeforces扩展包](https://download.csdn.net/download/weixin_42101164/18409501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值