bnuoj 52305 Around the World dfs+排列组合
来源:互联网 发布:亚马逊关键词优化方法 编辑:程序博客网 时间:2024/06/10 17:40
题意
n个城市,联通图,给出n-1条信息,表示城市A和城市B之间有2*C条无向路相连通。需求出从城市1开始,遍历所有边的方案数。
数据范围:
2 ≤ n ≤ 1e5
路的总数量不超过2*1e6
样例输入:
3
1 2 1
2 3 1
表示3个城市,1-2有2条路,2-3有三条路
题解
由于点数为1e5,静态链表方式存图。
求方案数的过程为深搜。
对于当前节点u来说,它有若干个字节点v1、v2、、、
ans[u]= ( ∑(num[u][vi]) )! * ∏( ( 2*num[u][vi] )! ) / ∏ ( num[u][vi] !) * ∏Lucas(out[vi] + num[u][vi] -1,num[u][vi]-1) * ∏ans[vi];
ps: num[u][vi]表示u->vi有2*num[u][vi]条边
表示这个递推公式让人根本不想看。。T_T
其实要做的只有两件事,遍历当前子节点的方案数,将子树与子树的遍历进行穿插的方案数。
先将每个子树看作一个节点,当前节点u有子节点v1、v2、、、vk,遍历当前子节点的方案数为ans[u] = out(u) ! /∏ ( num[u][vi] !) , out(u) = ∑(num[u][vi]), 为u的出度的一半。
同时,需考虑u-vi之间,边与边的不同:
ans[u] = ans[u] * ∏( ( 2*num[u][vi] )! )
其次,要将u-vi的进出穿插进vi子树本身的遍历中,同插空法,在out[vi]个小球中,插入num[u][vi]-1个隔板,将其分成num[u][vi]份,每一份>=0.
ans[u] = ans[u] * ∏Lucas(num[vi] + num[u][vi] -1,num[u][vi]-1)
最后,将子树的遍历方案数乘进来
ans[u] = ans[u] * ∏ans[vi];
代码
#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>using namespace std;typedef long long ll;#define mod 1000000007#define p 1000000007#define LL llconst ll MAX_N = 1e5+10;struct EDGE{ ll b; ll num; ll pre;}edge[MAX_N * 2];ll point[MAX_N];ll num[MAX_N];void add_edge(ll a,ll b,ll c,ll i){ edge[i].b = b; edge[i].num = c; edge[i].pre = point[a]; point[a] = i; num[a] = (num[a] + c)%mod;}ll half(ll x){ ll ans = 1LL; for(ll t = 2*x; t>x; t--) { ans = (ans*t)%mod; } return ans;}ll full(ll x){ ll ans = 1LL; for(ll t = x; t>0; t--) { ans = (ans*t)%mod; } return ans;}LL quick_mod(LL a, LL b) { LL ans = 1; a %= p; while(b) { if(b & 1) { ans = ans * a % p; b--; } b >>= 1; a = a * a % p; } return ans; } LL C(LL n, LL m) { if(m > n) return 0; LL ans = 1; for(int i=1; i<=m; i++) { LL a = (n + i - m) % p; LL b = i % p; ans = ans * (a * quick_mod(b, p-2) % p) % p; } return ans; } LL Lucas(LL n, LL m) { if(m == 0) return 1; return C(n % p, m % p) * Lucas(n / p, m / p) % p; } ll dfs(ll x, ll last, ll dec){ num[x] -= dec; ll ans = 0LL; ll add = 0LL; ll mul = 1LL; for(ll t = point[x];t!=-1;t = edge[t].pre) { ll v = edge[t].b; if(v == last) continue; add = (add + edge[t].num) % mod; mul = (mul * half(edge[t].num)) % mod; } add = full(add); ans = (add * mul)%mod; for(ll t = point[x];t!=-1;t = edge[t].pre) { ll v = edge[t].b; if(v == last) continue; ans = (ans * dfs(v, x, edge[t].num)) % mod; ll tans = 0LL; tans = (tans + Lucas( edge[t].num + num[v]-1, edge[t].num-1)) % mod; ans = (ans * tans) % mod; } return ans;}int main(){ ll n; while(scanf("%lld",&n)!=EOF) { memset(point,-1,sizeof(point)); memset(num,0,sizeof(num)); for(int i=1;i<n;i++) { ll a,b,c; scanf("%lld%lld%lld",&a,&b,&c); add_edge(a,b,c,i); add_edge(b,a,c,i+n-1); } ll ans = dfs(1,-1,0);; printf("%lld\n",ans); } return 0;}
其中lucas的模版来源于ACdreamers的博客组合数取模
- bnuoj 52305 Around the World dfs+排列组合
- bzoj3827:[Poi2014]Around the world
- BZOJ3827[Poi2014] Around the world
- BZOJ3827: [Poi2014]Around the world
- BNU-52305-Around the World(四川省赛H题)
- poj 2432 Around the world bfs+哈希
- 2016 四川省赛 Around the World
- CHILDBIRTH TRADITIONS AROUND THE WORLD: CHINA
- Ganymede Around the world中我的名字
- Around the World in Eighty Days 5/201
- Around the World in Eighty Days 19/201
- 【BZOJ3827】[Poi2014]Around the world【尺取法】【并查集】
- bzoj1748 [Usaco2005 open]Around the world 环球飞行
- 排列组合 dfs
- BNUOJ 39423 暴力,DFS
- hdu 1027 Ignatius and the Princess II【dfs 排列组合】
- ICPCCamp 2016 Day1 ftiasch's Contest #4(Around the world-树,构造)
- Around the World in 60 Days: Getting Deep Speech to Work in Mandarin
- 7. 模板引擎
- 在Unity3D中使用Visual Studio调试shader
- 8. CSS/JS 文件管理
- 【Poj2449】Remmarguts' Date-k短路(A*解法)
- 中文版iTween帮助文档、参数解析
- bnuoj 52305 Around the World dfs+排列组合
- 【LeetCode】103. Binary Tree Zigzag Level Order Traversal
- 编码问题
- 【29.70%】【codeforces 723D】Lakes in Berland
- 斜杠/和反斜杠\的区别
- 设计的原则
- 使用一个Github的Repository管理hexo网站源文件和发布文件
- printf参数,little endian,初始化列表来初始化
- CPU与GPU的区别