• [九省联考2018]秘密袭击coat


    传送门

    简要题意:求树上所有联通块中第k大的数的和。

    正解是肯定不会的……只会暴力……
    考虑一个简单的暴力,枚举当前第k大的数w,之后在树上跑树形背包,然后计算当前有多少个联通块满足至少k个元素大于w。
    这个算法会超时。然后这里有一些玄学的优化……
    首先如果一共也攒不够k个联通块就可以不DP了。然后这里我们考虑用(f[i][j])表示以i为根,满足联通块中有至少j个大于当前枚举的值的情况,这样转移的方程是:(f[x][min(j+p,k)] = f[x][min(j+p,k)] + f[e[i].to][p] * f[x][j]) 务必注意的是,(f[x][j])在DP过程中值会变化。所以要开临时变量存。

    听LK说,第一个优化在k大的时候有用第二个在k小的时候有用……然后结合上7秒的实现再开O2就过了……

    #include<bits/stdc++.h>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    using namespace std;
    typedef long long ll;
    const int mod = 64123;
    const int M = 200005;
    const int N = 10000005;
     
    int read()
    {
       int ans = 0,op = 1;char ch = getchar();
       while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
       while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
       return ans * op;
    }
    
    struct edge
    {
       int next,to,from;
    }e[M];
    int inc(int a,int b){return (a+b) % mod;}
    int mul(int a,int b){return 1ll * a * b % mod;}
    int n,k,w,d[M],head[M],ecnt,x,y,val[M],f[3000][5000],ans;
    bool can[M];
    
    void add(int x,int y)
    {
       e[++ecnt] = {head[x],y,x};
       head[x] = ecnt;
    }
    
    void dfs(int x,int fa)
    {
       val[x] = can[x];
       rep(i,0,k) f[x][i] = 0;
       f[x][can[x]] = 1;
       for(int i = head[x];i;i = e[i].next)
       {
          if(e[i].to == fa) continue;
          dfs(e[i].to,x);
          per(j,val[x],0)
          {
    	 int cur = f[x][j];
    	 per(p,val[e[i].to],0)
    	 f[x][min(j+p,k)] = inc(f[x][min(j+p,k)],mul(f[e[i].to][p],cur));
          }
          val[x] = min(k,val[x] + val[e[i].to]);
       }
    }
    
    int main()
    {
       n = read(),k = read(),w = read();
       rep(i,1,n) d[i] = read();
       rep(i,1,n-1) x = read(),y = read(),add(x,y),add(y,x);
       rep(q,1,w)
       {
          int cnt = 0;
          rep(i,1,n) cnt += (can[i] = (d[i] >= q));
          if(cnt < k) break;
          dfs(1,0);
          //rep(i,1,n) printf("#%d ",f[i][k]);
          rep(i,1,n) ans = inc(ans,f[i][k]);
       }
       printf("%d
    ",ans);
       return 0;
    }
    
    
  • 相关阅读:
    mysql调优
    面试、。。。。
    StringBuffer 和 StringBuilder 的 3 个区别
    msql查询指定日期
    Windows 路由跟踪
    Xdebug配置
    ONVIF流媒体播放流程
    Windows 8 SP1 安装StockTrader 6.1
    使用log4c问题
    xcode插件安装
  • 原文地址:https://www.cnblogs.com/captain1/p/10508223.html
Copyright © 2020-2023  润新知