给定一棵n个节点的树 有m条路径 问有多少种方案 使得 从m条路径里面选k条路径 这k条路径至少包含一个公共点
#include<bits/stdc++.h> using namespace std; const int N=3e5+6; const int mod=1e9+7; #define ll long long int head[N],pos,sum[N],n,m,k,fa[N][20],dep[N],cnt[N]; ll inv[N],fac[N]; struct Edge{int to,nex;}edge[N<<1]; void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;} void dfs(int x,int f) { fa[x][0]=f;dep[x]=dep[f]+1; for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to;if(v==f)continue; dfs(v,x); } } int getlca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=19; i>=0; --i) { if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; } if(x==y) return x; for(int i=19; i>=0; --i) { if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; } return fa[x][0]; } void dfs2(int x,int fa) { for(int i=head[x];i;i=edge[i].nex) { int v=edge[i].to; if(v==fa)continue; dfs2(v,x);sum[x]+=sum[v]; } } ll C(int n,int m) { if(n<m||m==0)return 0; return fac[n]*inv[m]%mod*inv[n-m]%mod; } ll calc(int x) { ll ans=C(sum[x],k); ans=(ans-C(sum[x]-cnt[x],k)%mod)%mod; return (ans+mod)%mod; } int main() { inv[0]=inv[1]=fac[1]=1; for(int i=2;i<=N;i++)fac[i]=fac[i-1]*i%mod; for(int i=2;i<=N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod; for(int i=2;i<=N;i++)inv[i]=inv[i-1]*inv[i]%mod; int cas;cin>>cas; while(cas--) { cin>>n>>m>>k;int u,v; for(int i=1;i<n;i++)scanf("%d%d",&u,&v),add(u,v),add(v,u); dfs(1,0); for(int j=1;j<20;j++) for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1]; while(m--) { scanf("%d%d",&u,&v); int lca=getlca(u,v); sum[u]++;sum[v]++; sum[lca]--;sum[fa[lca][0]]--; cnt[lca]++; } dfs2(1,0); ll ans=0; for(int i=1;i<=n;i++)ans+=calc(i),ans%=mod; cout<<ans<<endl; for(int i=1;i<=n;i++)sum[i]=head[i]=dep[i]=cnt[i]=0;pos=0; } return 0; }
2018 xuzhou icpc G. Rikka with Intersections of Paths
原文:https://www.cnblogs.com/bxd123/p/11707306.html