• codeforces 486D


    题意:

    给一棵树,每个点有个权值,求最大权值-最小权值<=d的连通块个数

    题解:

    枚举最大权值点作为根,可以算出最小权值最小是多少,然后树形dp,每次合并两个连通块dp[u]=dp[u]+dp[u]*dp[v] (原来的方案数+加入新连通块的方案数)

    树形dp中大于最大或者小于最小显然就不考虑了;

    我们考虑这样计数有什么问题:两个相同权值的点当最大权值的情况,同样的连通块会算两次;

    考虑怎么去重:如果v的标号>root的标号,那么就不考虑。

     1 #include<bits/stdc++.h>
     2 #define maxn 2005
     3 #define ll long long
     4 using namespace std;
     5 const ll mod = 1000000007;
     6 int n,d;
     7 int a[maxn];
     8 struct edge
     9 {
    10     int to,next;
    11 }e[maxn<<1];
    12 int head[maxn],p;
    13 void addedge(int u,int v)
    14 {
    15     e[++p].to=v;e[p].next=head[u];head[u]=p;
    16 }
    17 ll dp[maxn];
    18 void dfs(int u,int f,int minv,int maxv,int rt)
    19 {
    20     dp[u]=1;
    21     for(int i=head[u];i;i=e[i].next)
    22     {
    23         int v=e[i].to;
    24         if(v==f)continue;
    25         if(a[v]<minv)continue;
    26         if(a[v]>maxv||(a[v]==maxv&&v<rt))continue;
    27         dfs(v,u,minv,maxv,rt);
    28         dp[u]=(dp[u]+dp[u]*dp[v])%mod;
    29     }
    30 }
    31 int main()
    32 {
    33     scanf("%d%d",&d,&n);
    34     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    35     for(int i=1;i<n;++i)
    36     {
    37         int u,v;
    38         scanf("%d%d",&u,&v);
    39         addedge(u,v);
    40         addedge(v,u);
    41     }
    42     ll ans=0; 
    43     for(int u=1;u<=n;++u)
    44     {
    45         memset(dp,0,sizeof(dp));
    46         dfs(u,0,a[u]-d,a[u],u);
    47         ans+=dp[u];
    48         ans%=mod;
    49     }
    50     printf("%I64d
    ",ans);
    51     return 0;
    52 }
    View Code
  • 相关阅读:
    2018JAVA面试题附答案
    微服务概述
    Java后台开发面试题总结
    郁金香搜索引擎方案
    单点登录
    Redis为什么是单线程
    数据库原理-范式
    权限分配之一级菜单优化添加和编辑页面图标
    权限分配之一级菜单保留原搜索条件
    django分页的东西, 不详细, 但是也足够了。
  • 原文地址:https://www.cnblogs.com/uuzlove/p/10447926.html
Copyright © 2020-2023  润新知