2018.10.31-dtoj-4015-永琳的竹林迷径(path)

题目描述:

竹林可以看作是一个n 个点的树,每个边有一个边长i w ,其中有k 个关键点,永琳需
要破坏这些关键点才能走出竹林迷径。
然而永琳打算将这k 个点编号记录下来,然后随机排列,按这个随机的顺序走过k 个点,
但是两点之间她只走最短路线。初始时永琳会施展一次魔法,将自己传送到选定的k 个点中
随机后的第一个点。
现在永琳想知道,她走过路程的期望是多少,答案对998244353 取模。
注意,如果对期望不理解,题目最后有详细解释,请自行阅读。

输入:

第一行一个数Case,表示测试点编号。(样例的编号表示其满足第Case 个测试点的性
质)
下一行一个n,表示树的点数。
下面n-1 行,每行三个数i i i u,v,w ,表示一条边连接i i i u 和v,长度为w 。
下面一行一个数k,表示关键点数。
下面一行k 个数,表示k 个关键点的编号。

输出:

一行一个数,表示答案(对998244353 取模)。

数据范围:

对于100%的数据,保证 1≤ w ≤10 ,1≤N≤1e6,1≤K≤1e6

算法标签:DFS???概率期望

思路:

考虑对于每一条边对于答案会造成的贡献,当存在某两个选中的点在边的两边即存在情况使这条边出现次数++,根据这个思路退式子即可。

考差的不走心题解,式子都不给了

以下代码:

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e6+5,p=998244353;
int n,head[N],ne[N<<1],to[N<<1],v[N<<1],cnt,k,w[N],s[N];LL ans,base;
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il void insert(int x,int y,int z){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;v[cnt]=z;}
il LL ksm(LL a,int y){LL b=1;while(y){if(y&1)b=b*a%p;a=a*a%p;y>>=1;}return b;}
void dfs(int x,int fa){
    if(w[x])s[x]++;
    for(int i=head[x];i;i=ne[i]){
        if(fa==to[i])continue;
        dfs(to[i],x);s[x]+=s[to[i]];
        ans=(ans+(LL)s[to[i]]*(LL)(k-s[to[i]])%p*(LL)v[i]%p)%p;
    }
}
int main()
{
    //freopen("path.in","r",stdin);
    //freopen("path.in","w",stdout);
    read();n=read();for(int i=1;i<n;i++){int x=read(),y=read(),z=read();insert(x,y,z);insert(y,x,z);}
    k=read();for(int i=1;i<=k;i++)w[read()]=1;
    cnt=0;dfs(1,0);
    base=2ll*(LL)ksm((LL)k,p-2)%p;
    printf("%lld
",ans*base%p);
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/9882462.html