COGS 2096. 不平凡的许愿树
Posted 人间失格
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了COGS 2096. 不平凡的许愿树相关的知识,希望对你有一定的参考价值。
【题目描述】
noip要到了,大家来到许愿树前。这个许愿树不仅仅是许愿树,还有未卜先知的功能。众OIer问许愿树:“不平凡的许愿树,CCF告诉我们noip中会有两道题目从Openjudge上选择,你能不能告诉我是哪两道题。”
许愿树想了想直接说出答案并不妥:“中国有句古话叫‘闷声大发财’,我就什么也不说,这是最好的。但是我看到你们这么热情,一句话不说也不好,我就告诉你 们点信息吧。你们看我是一个由N个结点组成的树,在树中任选着3个点,有多少种选择方案使得这三个点互相之间的距离相同?两个方案不同当且仅当一个点在第 一种方案中被选择,第二种方案中没有被选择。”
“记你算出来方案数为cnt,那么第一道题的题号就是cnt%338 + 1,第二题的题目编号是(cnt+233)%338+1。”
可是OIer们手头并没有计算机,于是请你来告诉他们题目编号。
【输入格式】
第一行一个整数N,表示树有N个点。
接下来N-1行,每行两个整数u,v,表示树中有一条从u到v的边
【输出格式】
一行,两个整数,分别为预测的第一题题号和第二题题号。
【样例输入】
7 1 2 5 7 2 5 2 3 5 6 4 5
【样例输出】
6 239
【提示】
样例解释:
共有5种方案,分别是{1,3,5},{2,4,6},{2,4,7},{2,6,7},{4,6,7}。所以第一题的编号为5%338 + 1 = 6;第二题的编号为(5+233)%338 + 1 = 239;
数据范围与约定:
对于30%的数据:1 <= n <= 100
对于60%的数据:1 <= n <= 1500
对于100%的数据:1 <= n <= 5000
胡扯:
其实Openjudge没有确切题号,第1.1节有10题,第1.2节有10题...,不如约定第16题的编号是第1.2节的第6题。如果命中我什么都不知道。
题解:
这个题目思路还是比较清晰的。首先我们要知道一个结论,显然树上三点相互之间的最短路径的焦点有且只有一个。
那么这个题目就比比较好做了,我们可以枚举那个中心点然后算总方案数-不合法的方案数。
具体怎么做呢?可以考虑枚举每个点,以他为根dfs,求出每一层的点数(深度相同),然后显然总方案数等于所有的点在每一层选三个的组合数,相加。当然有不和法的情况:1.如果选中的三个点在同一棵子树里面的话那么显然就不和法。2.如果在一棵子数里面选了两个点,在另一棵子树又选一个点那么也是不合法的。那么我们每次dfs每个子树算一下对应的组合数就可以了。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #define ll long long #define MAXN 5010 #define mod 338 using namespace std; struct edge{ int first; int next; int to; }a[MAXN*2]; int c[MAXN][MAXN],dep[MAXN],dis[MAXN]; int n,num=0; ll ans=0; inline void addedge(int from,int to){ a[++num].to=to; a[num].next=a[from].first; a[from].first=num; } inline void dfs(int now,int f,int d,int *dep){ ++dep[d]; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(to==f) continue; dfs(to,now,d+1,dep); } } inline void pre(){ c[0][0]=1; for(int i=1;i<=n;i++){ c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } int main() { scanf("%d",&n); for(int i=1;i<n;i++){ int x,y;scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } pre(); for(register int now=1;now<=n;now++){ for(register int i=1;i<=n;i++) dep[i]=0; dfs(now,0,0,dep); for(register int k=1;k<=n;k++) ans+=c[dep[k]][3]%=mod; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; for(register int i=1;i<=n;i++) dis[i]=0; dfs(to,now,1,dis); for(register int k=1;k<=n;k++) ans+=mod-(c[dis[k]][3]+c[dis[k]][2]*(dep[k]-dis[k]))%mod; if(ans>=mod) ans-=mod; } } printf("%lld %lld",ans%mod+1,(ans+233)%mod+1); return 0; }
以上是关于COGS 2096. 不平凡的许愿树的主要内容,如果未能解决你的问题,请参考以下文章