[dp][递归] Jzoj P4211 送你一棵圣诞树

Description

再过三个多月就是圣诞节了,小R 想送小Y 一棵圣诞树作为节日礼物。因为他想让这棵圣诞树越大越好,所以当然是买不到能够让他满意的树的,因此他打算自己把这棵树拼出来。
现在,小R 开始画这棵树的设计图纸了。因为这棵树实在太大,所以他采用了一种比较方便的方法。首先他定义了m+ 1 棵树T0 到Tm。最开始他只画好了T0 的图纸:就只有一个点,编号为0。
接着,对于每一棵树Ti,他在第Tai 棵树的第ci 个点和第Tbi 棵树的第di 个点之间连上了一条长度为li 的边。在Ti 中,他保持Tai 中的所有节点编号不变,然后如果Tai 中有s 个节点,他会把Tbi 中的所有节点的编号加上s。
终于,他画好了所有的树。现在他定义一颗大小为n 的树的美观度为,其中d(i; j) 为这棵树中i 到j 的最短距离。
为了方便小R 选择等究竟拼哪一棵树,你可以分别告诉他T1 到Tm 的美观度吗?答案可能很大,请对10^9 + 7 取模后输出。

Input

第一行输入一个正整数T 表示数据组数。每组数据的第一行是一个整数m,接下来m 行每行五个整数ai, bi, ci, di, li,保证0 <= ai, bi < i, 0<= li<= 10^9,ci, di 存在。

Output

对于每组询问输出m 行。第i 行输出Ti 的权值

Sample Input

120 0 0 0 21 1 0 0 4

Sample Output

228

Data Constraint

对于30% 的数据,m <= 8
对于60% 的数据,m <= 16
对于100% 的数据,1 <= m<= 60,T<= 100

题解

  • 题目大意:给定了n棵树,每次会奖两棵树中的x,y之间连一条len的边,也就是将两棵树合并,问每棵树上两两点对的最短路径和
  • 设calc1(x,y)为x这棵树里,其他点到y的最短路径和,calc2(x,y,k)为x这棵树里,y到k的最短路径长度
  • 设f[i]为第i棵数的答案,f[i]=f[i.left]+f[i.right]+calc1(i.left,i.c)*i.right.size+calc1(i.right,i.d)*i.left.size+i.len*i.left.size*i.right.size
  • calc1(x,y)中可以分成两种情况,①在x的左子树②在x的右子树
  • 当在x的左子树时calc1(x,y)=calc1(x.left,y)+(calc2(y,x.left,x.c)+x.len)*x.right.size+calc1(x.right,x.d),但在右子树里也是同理
  • calc2(x,y,z)也可以想上面分成两种情况,①y和k在同一棵子树里②y和k不在同一棵子树里
  • 当在它们在同一颗子树里,直接往下递归;当它们不在同一棵子树里时,calc2(x,y,z)=calc2(x.left,y,x.c)+calc2(x.right,z,x.d)+x.len
  • 这题比较恶心,还要用map优化

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<map>
 5 #define ll long long
 6 using namespace std;
 7 const ll N=70,mo=1e9+7;
 8 ll T,n,f[N];
 9 typedef pair<ll,ll> node;
10 struct edge{ ll a,b,size,c,d,v; }p[N];
11 map <node,ll> Q[N];
12 ll calc2(ll k,ll x,ll y)
13 {
14     if (x>y) swap(x,y);
15     if (k==0||x==y) return 0;
16     if (x<p[p[k].a].size&&y<p[p[k].a].size) return calc2(p[k].a,x,y);
17     else if (x>=p[p[k].a].size&&y>=p[p[k].a].size) return calc2(p[k].b,x-p[p[k].a].size,y-p[p[k].a].size);
18     else
19     {
20         node q=make_pair(x,y);
21         if (Q[k].find(q)!=Q[k].end()) return Q[k][q];
22         return Q[k][q]=(calc2(p[k].a,p[k].c,x)+calc2(p[k].b,p[k].d,y-p[p[k].a].size)+p[k].v)%mo;
23     }
24 }
25 ll calc1(ll k,ll x)
26 {
27     ll r=0; node q=make_pair(x,0);
28     if (Q[k].find(q)!=Q[k].end()) return Q[k][q];
29     if (k==0) return 0;
30     if (x<p[p[k].a].size) r=(calc1(p[k].a,x)+calc1(p[k].b,p[k].d))%mo+(((p[k].v+calc2(p[k].a,p[k].c,x))%mo)*(p[p[k].b].size%mo))%mo;
31     else r=(calc1(p[k].a,p[k].c)+calc1(p[k].b,x-p[p[k].a].size))%mo+(((p[k].v+calc2(p[k].b,p[k].d,x-p[p[k].a].size))%mo)*(p[p[k].a].size%mo)%mo);
32     return (Q[k][q]=r)%mo;
33 }
34 int main()
35 {
36     freopen("data.in","r",stdin);
37     scanf("%d",&T);
38     while (T--)
39     {
40         scanf("%d",&n),memset(p,0,sizeof(p)),p[0].size=1;
41         for (int i=1;i<=n;i++) scanf("%lld%lld%lld%lld%lld",&p[i].a,&p[i].b,&p[i].c,&p[i].d,&p[i].v),p[i].size=p[p[i].a].size+p[p[i].b].size,Q[i].clear();
42         for (int i=1;i<=n;i++)
43             f[i]=((f[p[i].a]+f[p[i].b])%mo+(calc1(p[i].a,p[i].c)*(p[p[i].b].size%mo)+(calc1(p[i].b,p[i].d)*(p[p[i].a].size%mo))%mo
44                 +(((p[i].v%mo)*(p[p[i].a].size%mo))%mo*(p[p[i].b].size%mo))%mo)%mo)%mo,
45             printf("%lld\n",f[i]);
46     }
47 }

原文地址:https://www.cnblogs.com/Comfortable/p/10317133.html

时间: 2024-07-28 23:01:00

[dp][递归] Jzoj P4211 送你一棵圣诞树的相关文章

poj 1088(DP+递归)

这题状态方程很容易得到:DP[i][j] = max(DP[i-1][j],DP[i+1][j],DP[i][j-1],DP[i][j+1]) + 1 难点在于边界条件和剪枝,因为这方程的条件是点在map里,且只有递增关系才会变化,如果用循环的话要判断递增,所以用递归比较方便 #include <iostream> #include <string> #include <cstring> #include <cstdlib> #include <cst

DP(递归打印路径) UVA 662 Fast Food

题目传送门 题意:n个饭店在一条直线上,给了它们的坐标,现在要建造m个停车场,饭店没有停车场的要到最近的停车场,问所有饭店到停车场的最短距离 分析:易得区间(i, j)的最短距离和一定是建在(i + j) / 2的饭店,预处理出(i, j)的距离和sum[i][j],mark[i][j] 表示区间的最优停车场的位置,mid[i][j]表示(i + j) / 2.状态转移方程:dp[i][j] = max (dp[k-1][j-1] + sum[k][i]): 收获:学习递归打印路径 代码: /*

uva 10453 Make Palindrome (区间DP + 递归输出)

uva 10453 Make Palindrome 题目大意:给出一段字符串,要求求出最少加入几个字符(任意位置),可以让该字符串变成会问字符串,并输出修改以后的回文字符串. 解题思路:dp[i][j]代表了将该字符串从第i位到第j位变成回文字符串最少要添加的字符.当S[i]==S[j],dp[i][j]=dp[i+1][j?1]当S[i]!=S[j],dp[i][j]=min(dp[i+1][j],dp[i][j?1])+1,在DP的过程中记录对该区间的操作类型,最后递归输出. #includ

HDU5092——DP+递归输出——Seam Carving

Problem Description Fish likes to take photo with his friends. Several days ago, he found that some pictures of him were damaged. The trouble is that there are some seams across the pictures. So he tried to repair these pictures. He scanned these pic

zoj 3640 Help Me Escape (概率dp 递归求期望)

题目链接 Help Me Escape Time Limit: 2 Seconds      Memory Limit: 32768 KB Background     If thou doest well, shalt thou not be accepted? and if thou doest not well, sin lieth at the door. And unto thee shall be his desire, and thou shalt rule over him.  

poj 1141 区间dp+递归打印路径

Brackets Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30383   Accepted: 8712   Special Judge Description Let us define a regular brackets sequence in the following way: 1. Empty sequence is a regular sequence. 2. If S is a re

[DP][二分]JZOJ 3463 军训

Description HYSBZ 开学了!今年HYSBZ 有n 个男生来上学,学号为1-n,每个学生都必须参加军训.在这种比较堕落的学校里,每个男生都会有Gi 个女朋友,而且每个人都会有一个欠扁值Hi.学校为了保证军训时教官不会因为学生们都是人生赢家或者是太欠扁而发生打架事故,所以要把学生们分班,并做出了如下要求: 1.分班必须按照学号顺序来,即不能在一个班上出现学号不连续的情况. 2.每个学生必须要被分到某个班上. 3.每个班的欠扁值定义为该班中欠扁值最高的那名同学的欠扁值.所有班的欠扁值之

[计数dp][数学] Jzoj P4254 集体照

Description 一年一度的高考结束了,我校要拍集体照.本届毕业生共分n个班,每个班的人数为Ai.这次拍集体照的要求非常奇怪:所有学生站一排,且相邻两个学生不能同班.现在,安排这次集体照的老师找到了你,想问问你一共有多少种方案.方案数可能很大,最终结果对1,000,000,007取模. Input 输入文件名为photo.in.第一行为为一个整数n.第二行为n个正整数,分别为每个班的人数. Output 输出文件photo.out,共1行,为总方案数. Sample Input 输入1:

[状压DP][DFS]JZOJ 2679 跨时代

Description 钟逆时针而绕,恶物狰狞的倾巢,我谦卑安静地于城堡下的晚祷,压抑远古流窜的蛮荒暗号,而管风琴键高傲的说,那只是在徒劳.我的乐器在环绕,时代无法淘汰我霸气的皇朝. 你无法预言,因为我越险,翅越艳:没有句点,跨时代蔓延,翼朝天. 月下浮雕,魔鬼的浅笑,狼迎风嚎,蝠翔似黑潮,用孤独去调尊严的色调.我跨越过世代,如兽般的姿态,琴声唤起沉睡的血脉.不需要被崇拜,如兽般的悲哀,只为永恒的乐曲存在,醒过来. 去年万众瞩目的<跨时代>专辑发行之后,周杰伦又开始了他的世界巡回演唱会<