1. 程式人生 > >LOJ #2473. 「九省聯考 2018」秘密襲擊

LOJ #2473. 「九省聯考 2018」秘密襲擊

getc 多少 節點 tchar getchar cmp else += ref

#2473. 「九省聯考 2018」秘密襲擊

鏈接

分析:

  首先枚舉一個權值W,計算這個多少個連通塊中,第k大的數是這個權值。

  $f[i][j]$表示到第i個節點,有j個大於W數的連通塊的個數。然後背包轉移。

  復雜度是$O(n^2k)$,時限5s,然後卡卡常就過了。

代碼:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include
<set> #include<queue> #include<vector> #include<map> using namespace std; typedef unsigned int ui; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==-)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f; } const
int N = 2005, mod = 64123; struct Edge{ int to, nxt; } e[N << 1]; int head[N], id[N], fa[N], st[N], ed[N], a[N]; ui f[N][N]; int n, k, w, Now, En; inline bool cmp(int x,int y) { return a[x] == a[y] ? x <= y : a[x] < a[y]; } inline void add_edge(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En; } void dfs(int u) { for (int i = st[u]; i <= ed[u]; ++i) f[u][i] = 0; if (cmp(Now, u)) st[u] = ed[u] = 1; else st[u] = ed[u] = 0; f[u][st[u]] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa[u]) continue; fa[v] = u; dfs(v); for (int j = ed[u]; j >= st[u]; --j) for (int k = ed[v]; k >= st[v]; --k) f[u][j + k] = (f[u][j + k] + f[u][j] * f[v][k]) % mod; ed[u] += ed[v]; } for (int i = st[u]; i <= ed[u]; ++i) f[0][i] = (f[0][i] + f[u][i]) % mod; } int main() { n = read(), k = read(), w = read(); for (int i = 1; i <= n; ++i) a[i] = read(); for (int i = 1; i < n; ++i) { int u = read(), v = read(); add_edge(u, v); } for (int i = 1; i <= n; ++i) id[i] = i; sort(id + 1, id + n + 1, cmp); ui ans = 0; for (int i = 1; i <= n; ++i) { memset(f[0], 0, sizeof(f[0])); Now = id[i]; dfs(1); for (int j = k; j <= n; ++j) ans = (ans + f[0][j] * (a[id[i]] - a[id[i - 1]])) % mod; } cout << ans % mod; return 0; }

LOJ #2473. 「九省聯考 2018」秘密襲擊