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

Posted captain1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[九省联考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;
}

以上是关于[九省联考2018]秘密袭击coat的主要内容,如果未能解决你的问题,请参考以下文章

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

bzoj5250 [九省联考2018]秘密袭击coat 树形dp

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

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

解题:九省联考2018 秘密袭击CoaT

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