标签:math tin inpu lld stream 节点 algorithm NPU tor
传送门:https://codeforces.com/contest/110/problem/E
题意:给你一颗树,节点与节点之间的边有一个边权,定义只由4和7组成的数字是幸运数字,现在要你求一共有多少条路径,使得节点u->v之间至少存在一条边为幸运数字
题解:树形dp+容斥,我们要找有多少条路径上至少存在一条幸运边,那么我们就可以找到所有的不含幸运路径的边然后用所有路径和减去不含幸运路径的边即可
1,每次输入边权的时候处理边权是否为幸运数字,如果是,那么为1,否则为0
2,dfs处理,如果边权为0,那么不含幸运数字的路径+1;
3,容斥,有t条不含幸运数字的边则一共有t*(t-1)*(t-2)种方法,因为是双向边,所以容斥第二次的时候记得*2;
代码如下:
#include <map> #include <set> #include <cmath> #include <ctime> #include <stack> #include <queue> #include <cstdio> #include <cctype> #include <bitset> #include <string> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #include <functional> #define fuck(x) cout<<"["<<x<<"]"; #define FIN freopen("input.txt","r",stdin); #define FOUT freopen("output.txt","w+",stdout); //#pragma comment(linker, "/STACK:102400000,102400000") using namespace std; typedef long long LL; typedef pair<int, int> PII; const int maxn = 1e5+5; const int INF = 0x3f3f3f3f; const int MOD = 1e9+7; struct node{ int v,next; LL w; }edge[maxn<<2]; int head[maxn],tot; LL dp[maxn]; void add(int u,int v,int w){ edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } void dfs(int u,int fa){ dp[u]=0; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa) continue; dfs(v,u); if(edge[i].w==0){ dp[u]+=dp[v]+1; dp[v]=0; } } } int main(){ #ifndef ONLINE_JUDGE FIN #endif int u,v; LL n,w,f; tot=0; memset(head,-1,sizeof(head)); scanf("%lld",&n); for(int i=1;i<n;i++){ scanf("%d%d%lld",&u,&v,&w); f=1; while(w){ if(w%10!=4&&w%10!=7) f=0; w/=10; } add(u,v,f); add(v,u,f); } if(n<=2){ printf("0\n"); return 0; } dfs(1,1); LL ans=(LL)n*(n-1)*(n-2); for(int i=1;i<=n;i++){ if(dp[i]){ LL tmp=dp[i]+1; ans-=tmp*(tmp-1)*(tmp-2); ans-=tmp*(tmp-1)*((LL)n-tmp)*2; } } cout<<ans<<endl; }
标签:math tin inpu lld stream 节点 algorithm NPU tor
原文地址:https://www.cnblogs.com/buerdepepeqi/p/9515185.html