A. 树与路径(树论/多项式/分治FFT)

23 篇文章 0 订阅
10 篇文章 0 订阅

A. 树与路径

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
首先考虑一个dp的方法,对于这种链划分的题目,有一个很重要的思想就是按照每个点的角度考虑,实际上链划分就是匹配问题,每个点只能出一条边和入一条边,所以我们拆点之后就是匹配,这也是网络流最少链覆盖的思路。

这道题是在树上那么就有更好的性质,实际上对于每个点的状态就是将所连接的边进行匹配,并且每个点的状态是独立的,所以我们可以考虑一个暴力的dp, d p i , j dp_{i,j} dpi,j表示的是i这个点包含父亲边划分为j条链的方案数,然后可以得到转移如果没有链经过i,那么直接相乘,否则假设有k条链经过,则需要乘上一个系数
( 2 k d u i ) ( 2 k − 1 ) ! ! \binom{2k}{du_i}(2k-1)!! (dui2k)(2k1)!!
意义为选择2k个点进行匹配,然后2n个点的完美匹配个数为(2n-1)!!,这是一个经典结论,具体可以通过枚举1号点的匹配递推出来。
f n = ( n − 1 ) f n − 2 f_n=(n-1)f_{n-2} fn=(n1)fn2

然后由于整个问题每个点都是独立的,并且可以看出这也是一个背包问题,所以我们可以利用多项式求解。直接在将上面的系数看作是关于k的多项式,然后乘起来最终的系数就是答案。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一段多项式加法的代码,完整代码如下: ```c++ #include <stdio.h> #include <stdlib.h> typedef struct PolyNode { int Coef; // 多项式系数 int Exp; // 多项式指数 struct PolyNode* next; // 链接指针 }PolyNode, * PolyList; PolyList CreateEmptyPoly(PolyList Head_Ptr); void ClearPoly(PolyList HeadPtr); void DestroyPoly(PolyList HeadPtr); void PrintPoly(PolyList HeadPtr); void CreatePolyByKeyboard(PolyList HeadPtr); void AddPoly(PolyList PolyA_Head, PolyList PolyB_Head); int main() { PolyList PolyA_HeadPtr, PolyB_HeadPtr; PolyA_HeadPtr = CreateEmptyPoly(PolyA_HeadPtr); PolyB_HeadPtr = CreateEmptyPoly(PolyB_HeadPtr); printf("请输入多项式 A 的系数和指数:\n"); CreatePolyByKeyboard(PolyA_HeadPtr); printf("多项式 A = "); PrintPoly(PolyA_HeadPtr); printf("请输入多项式 B 的系数和指数:\n"); CreatePolyByKeyboard(PolyB_HeadPtr); printf("多项式 B = "); PrintPoly(PolyB_HeadPtr); AddPoly(PolyA_HeadPtr, PolyB_HeadPtr); printf("多项式 A + B = "); PrintPoly(PolyA_HeadPtr); DestroyPoly(PolyA_HeadPtr); DestroyPoly(PolyB_HeadPtr); return 0; } PolyList CreateEmptyPoly(PolyList Head_Ptr) { PolyNode* p = (PolyNode*)malloc(sizeof(PolyNode)); p->next = NULL; Head_Ptr = p; return Head_Ptr; } void ClearPoly(PolyList HeadPtr) { PolyNode* p, * q; p = HeadPtr->next; while (p != NULL) { q = p->next; free(p); p = q; } HeadPtr->next = NULL; } void DestroyPoly(PolyList HeadPtr) { ClearPoly(HeadPtr); free(HeadPtr); } void PrintPoly(PolyList HeadPtr) { PolyNode* p = HeadPtr->next; int flag = 0; if (p == NULL) { printf("0\n"); return; } while (p != NULL) { if (flag == 0) { printf("%d*x^%d", p->Coef, p->Exp); flag = 1; } else { if (p->Coef > 0) printf(" + %d*x^%d", p->Coef, p->Exp); else if (p->Coef < 0) printf(" - %d*x^%d", -p->Coef, p->Exp); } p = p->next; } printf("\n"); } void CreatePolyByKeyboard(PolyList HeadPtr) { int coef, exp; PolyNode* p = HeadPtr; scanf_s("%d %d", &coef, &exp); while (exp != -1) { PolyNode* q = (PolyNode*)malloc(sizeof(PolyNode)); q->Coef = coef; q->Exp = exp; q->next = NULL; p->next = q; p = q; scanf_s("%d %d", &coef, &exp); } } void AddPoly(PolyList PolyA_Head, PolyList PolyB_Head) { PolyNode* p, * q, * r, * t; int sum; p = PolyA_Head->next; q = PolyB_Head->next; r = PolyA_Head; // 'r' 指针总是指向 'p' 的前一个节点 ... t = NULL; // 对 'B' 多项式链表中节点的处理, 要么释放掉, 要么加入 'A' 多项式链表, 所以直接将其置空 ... PolyB_Head->next = NULL; while ((p != NULL) && (q != NULL)) { if ((p->Exp) < (q->Exp)) { r = p; p = p->next; } else if (p->Exp == q->Exp) { sum = p->Coef + q->Coef; if (sum != 0) { p->Coef = sum; r = p; p = p->next; t = q; q = q->next; free(t); } else { t = p; p = p->next; free(t); t = q; q = q->next; free(t); } } else // 'p -> Exp > q -> Exp' ... { t = q->next; q->next = p; r->next = q; r = q; q = t; } } // end 'while ( ( p != NULL ) && ( q != NULL ) )' ... // 若 'B' 链表为空, 将剩下的节点链接起来 ... if (p != NULL) r->next = p; // 若 'A' 链表为空, 将剩下的节点链接起来 ... if (q != NULL) r->next = q; } ``` 这段代码实现了多项式的加法,其中 `PolyNode` 为结构体类型,存储了多项式的系数和指数,`PolyList` 为指向 `PolyNode` 的指针类型,表示多项式链表的头指针。`CreateEmptyPoly` 函数用于创建一个空的多项式链表,`ClearPoly` 函数用于清空多项式链表中的所有节点,`DestroyPoly` 函数用于销毁整个多项式链表,`PrintPoly` 函数用于输出多项式,`CreatePolyByKeyboard` 函数用于通过键盘输入创建多项式,`AddPoly` 函数实现了多项式的加法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值