zoukankan      html  css  js  c++  java
  • 【2020NOI.AC省选模拟#6】A. zyb的监控计划

    题目链接

    原题解:

    考虑我们需要的信息:子树里最浅的一个能向上的点是谁?子树里最深的一个没被覆盖的深度是多少?

    我们记录一下$f_{i,a,b}$表示上面两个信息为$a$和$b$的时候,最少要花费的代价。

    转移的时候枚举$c,d$进行转移,看起来就很麻烦。

    然后我们注意一个结论:考虑如果$ageq b$的话,这个$b$其实是$0$,而如果$a<b$的话,证明之后存在一个节点$x$,到$i$之后剩余能覆盖的距离至少是$b$,所以$a$和$b$中一定有一个信息是没用的。

    我们令$f_{i,a}$表示存在一个还能覆盖是$a$的点,$g_{i,b}$表示存在一个深度为$b$的还没覆盖的点。

    考虑暴力转移,可以通过前缀和优化直接做到$O(NK)$。

    补充:

    从找到“有用信息”这一步我就被拒之门外了。。。

    然后“有用信息”之间也是有相互影响的关系的。搞清楚本质有助于优化DP。

    代码(100分):

    #include<cstdio>
    #include<cstring>
    #define K 202
    #define M 200002
    #define N 100001
    inline int min(int x,int y){return x<y?x:y;}
    int a[N],b[M],c[M],e[N],f[N][K],g[K],m,n;
    void dfs(int u,int v)
    {
        for(int i=0;i<=m;i++)f[u][i]=1000000000;
        for(int&i=a[u];i;i=b[i])if(c[i]!=v)
        {
            dfs(c[i],u);
            for(int j=0;j<m;j++)g[j+1]=min(g[j+1],f[c[i]][j]+f[u][m+m-j]);
            for(int j=m;j<=m<<1;j++)g[m+m-j]=min(g[m+m-j],f[c[i]][j]+f[u][m+m-j]);
            for(int j=m;j<=m<<1;j++)g[j+1]=f[c[i]][j]+f[u][j+1];
            for(int j=1;j<=(m<<1|1);j++)f[u][j]=min(f[u][j-1],g[j]),g[j]=1000000000;
        }
        for(int i=0;f[u][m<<1|1]+e[u]<f[u][i];i++)f[u][i]=f[u][m<<1|1]+e[u];
    }
    int i,u,v;
    int main()
    {
        for(scanf("%d%d",&n,&m),i=1;i<=(m<<1|1);i++)g[i]=1000000000;
        for(i=1;i<=n;i++)scanf("%d",e+i);
        for(i=1;i<n;i++)scanf("%d%d",&u,&v),b[i<<1]=a[u],c[a[u]=i<<1]=v,b[i<<1|1]=a[v],c[a[v]=i<<1|1]=u;
        return 0&(dfs(1,0),printf("%d
    ",f[1][m]));
    }
    View Code
  • 相关阅读:
    同名覆盖引发的问题
    矩阵快速幂模板题
    矩阵快速幂模板
    常见的代码错误情况
    十进制快速幂
    用唯一分解定理求m/n
    map用法
    游戏通关
    排序
    初识《设计模式》
  • 原文地址:https://www.cnblogs.com/Hansue/p/13055068.html
Copyright © 2011-2022 走看看