题目链接:点击打开链接
题意:
给定n个点的树,有边权。
定义lucky number:数字只有4或7组成
对于一个三元组(i, j, k)
若path(i,j) 路径上的数字存在lucky number && path(i,k) 路径上的数字存在lucky number
则三元组合法。
问有多少个合法的三元组。
( (i,j,k) != (i,k,j) )
用全集-补集。dfs出每个只由 非lucky number 构成的联通块 的点数 x 。
然后方法数就是 x*(x-1)*(x-2) + x*(x-1) * (n-x) * 2
#include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define ll long long #define N 100100 bool fix(int x){ if(x == 0)return false; while(x){ int y = x%10; if(y!=4 && y!=7)return false; x /= 10; } return true; } struct Edge{ int from, to, val, nex; }edge[N<<2]; int head[N], edgenum; void add(int u, int v, int val){ Edge E = {u, v, val, head[u]}; edge[edgenum] = E; head[u] = edgenum++; } ll dp[N]; ll dfs(int u, int fa){ dp[u] = 0; for(int i = head[u]; ~i; i = edge[i].nex){ int v = edge[i].to; if(v == fa)continue; dfs(v, u); if(edge[i].val == 0){ dp[u] += dp[v]+1; dp[v] = 0; } } } void init(){memset(head, -1, sizeof head); edgenum = 0;} int n; void solve(){ int i, j, u, v, val; init(); for(i = 1; i < n; i++) { scanf("%d %d %d",&u,&v,&val); add(u, v, val); add(v, u, val); } if(n<=2){puts("0");return ;} for(i = 0; i < edgenum; i+=2)edge[i].val = edge[i^1].val = fix(edge[i].val); ll all = (ll)n; all = all * (all-1) *(all-2); dfs(1, 1); for(i = 1; i <= n; i++) if(dp[i]){ ll ans = dp[i] +1; all -= ans * (ans-1) * (ans-2); all -= ans * (ans-1) * ((ll)n - ans) * 2LL; } cout<<all<<endl; } int main(){ while(~scanf("%d",&n)){ solve(); } return 0; }
时间: 2024-10-08 11:54:35