您的位置:首页 > 其它

Codeforces 543D. Road Improvement (树dp + 乘法逆元)

2016-09-27 16:06 471 查看
题目链接:http://codeforces.com/contest/543/problem/D

给你一棵树,初始所有的边都是坏的,要你修复若干边。指定一个root,所有的点到root最多只有一个坏边。以每个点为root,问分别有多少种方案数。

dp[i]表示以i为子树的root的情况数,不考虑父节点,考虑子节点。 dp[i] = dp[i] * (dp[i->son] + 1)

up[i]表示以i为子树的root的情况数(倒着的),考虑父节点,不考虑子节点。 这里需要逆元。 注意(a/b)%mod中b%mod=0是错误的,所以要特殊判断。

//#pragma comment(linker, "/STACK:102400000, 102400000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
typedef long long LL;
typedef pair <int, int> P;
const int N = 2e5 + 5;
LL dp
, mod = 1e9 + 7, up
;
vector <int> edge
;
int cnt
; //子树(dp[i->son] + 1)%mod != 0的节点数
LL fuck
; //子树(dp[i-son] + 1)%mod != 0的方案数相乘

LL fpow(LL a, LL n) {
LL res = 1;
while(n) {
if(n & 1)
res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res;
}

void dfs1(int u, int p) {
dp[u] = 1;
fuck[u] = 1;
for(int i = 0; i < edge[u].size(); ++i) {
int v = edge[u][i];
if(v == p)
continue;
dfs1(v, u);
if(dp[v] + 1 == mod)
cnt[u]++;
else
fuck[u] = (1 + dp[v]) % mod * fuck[u] % mod;
dp[u] = (1 + dp[v]) % mod * dp[u] % mod;
}
}

void dfs2(int u, int p) {
for(int i = 0; i < edge[u].size(); ++i) {
int v = edge[u][i];
if(v == p)
continue;
//LL temp = dp[u] * fpow((dp[v] + 1) % mod, mod - 2) % mod; //error
LL temp = 0;
if(dp[v] + 1 == mod && up[u] && cnt[u] == 1) {   //特殊情况
temp = fuck[u];
} else {
temp = dp[u] * fpow((dp[v] + 1) % mod, mod - 2) % mod;
}
up[v] = (up[u] * temp % mod + 1) % mod;
dfs2(v, u);
}
}

int main()
{
int n, u;
scanf("%d", &n);
for(int i = 2; i <= n; ++i) {
scanf("%d", &u);
edge[i].push_back(u);
edge[u].push_back(i);
}
dfs1(1, -1);
up[1] = 1;
dfs2(1, -1);
for(int i = 1; i <= n; ++i) {
printf("%lld%c", dp[i]*up[i]%mod, i == n ? '\n': ' ');
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: