1 条题解
-
0
自动搬运
来自洛谷,原作者为

cmd2001
rm -rf ~搬运于
2025-08-24 21:39:53,当前版本为作者最后更新于2017-11-07 16:17:09,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
其实树状DP也可以做的,而且复杂度比点分治低......
我们定义 f[x][0,1,2] 表示在点x及其子树中,距离点x的距离在模3意义下为0,1,2的点分别有多少个。
转移的话直接从子树加上边长转移。
统计答案时需要在转移某一个子树前进行统计。其实就是一个卷积(雾?说人话!),说白了就是让 前面的子树的点到点x的距离 与 当前子树中的点到点x的距离 在模3意义下为0。因为点对有序,所以乘2。
初值为f[x][0]=1。最后答案加上 每个点到本身的方案书(其实就是n) , 去和n*n取gcd即可。
最后上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #define debug cout using namespace std; const int maxn=2e4+1e2; int s[maxn],t[maxn<<1],nxt[maxn<<1],l[maxn<<1]; int f[maxn][3]; int n,ans,full,g; inline void addedge(int from,int to,int len) { static int cnt = 0; t[++cnt] = to; l[cnt] = len; nxt[cnt] = s[from]; s[from] = cnt; } inline int mod(int x) { return (x%3+3)%3; } inline int gcd(int x,int y) { if( ! ( x && y ) ) return x | y; register int t; while( t = x % y ) x = y , y = t; return y; } inline void dfs(int pos,int fa) { f[pos][0] = 1; for(int at=s[pos];at;at=nxt[at]) { if( t[at] == fa ) continue; dfs(t[at],pos); for(int i=0;i<3;i++) ans += f[t[at]][i] * f[pos][mod(-i-l[at])] * 2; for(int i=0;i<3;i++) f[pos][mod(i+l[at])] += f[t[at]][i]; } } inline int getint() { int ret = 0 , fix = 1; char ch = getchar(); while( ! isdigit(ch) ) fix = ch == '-' ? -1 : fix, ch = getchar(); while( isdigit(ch) ) ret = ret * 10 + ( ch - '0' ), ch = getchar(); return ret * fix; } int main() { n = getint(); for(int i=1,a,b,l;i<n;i++) { a = getint() , b = getint() , l = getint(); addedge(a,b,l); addedge(b,a,l); } dfs(1,-1); ans += n; full = n * n; g = gcd( ans , full ); ans /= g , full /= g; printf("%d/%d\n",ans,full); return 0; }
- 1
信息
- ID
- 1674
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者