首先,这道题正解的思路是从subtask2而得来的,所以先讲一下subtask2的做法。
因为保证答案不超过long long,所以直接求最大权独立集即可:dp[u][0]表示u点一定不能取的答案,dp[u][1]表示u点对儿子没有限制的答案。
\(dp[u][0]=max(dp[v][0],dp[v][1])\)
\(dp[u][1]=max(dp[u][1],val[u]*\prod dp[v][0])\)
直接跑DP即可。
而正解是怎么做的呢?
想到乘法,可以将其转化为对数,每次乘法就相当于对数相加,这个就可以计算出怎样选取这个最大权独立集,再跑一遍深搜统计答案即可。
//这里的dp的都是对数,所以只用相加即可
void dfs(int u,int fa)
{
dp[u][0]=dp[u][1]=0;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v!=fa)
{
dfs(v,u);
dp[u][0]+=max(dp[v][0],dp[v][1]);
dp[u][1]+=dp[v][0];
}
}
dp[u][1]+=logv[u];
}
\\统计答案的时候通过已经求出来的dp来作决策
\\如果u本身被选,肯定儿子不可选
\\如果u本身没有被选,判断儿子选更优还是不选更优。
\\选的话要乘上val
long long dfs1(int u,int fa,int yes)
{
long long ans=1;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v!=fa)
{
if(yes)
{
ans=(ans*dfs1(v,u,0))%mod;
}else{
if(dp[v][0]>dp[v][1])
{
ans=(ans*dfs1(v,u,0))%mod;
}else{
ans=(ans*dfs1(v,u,1))%mod;
}
}
}
}
if(yes)
{
ans=(ans*val[u])%mod;
}
return ans;
}
if(dp[1][0]>dp[1][1])
{
printf("%lld\n",dfs1(1,-1,0));
}else{
printf("%lld\n",dfs1(1,-1,1));
}