秘密襲擊 BZOJ5250 樹形DP

2022-05-16 05:11:13 字數 1642 閱讀 4902

分析:

聽說正解是fft+線段樹合併,然而我並不會...

我們來思考其他的方法。

我們要求的是連通塊第k大的和

對於某乙個連通塊,對答案的貢獻=val(rank.k)

我們不好直接算出每個連通塊的rank.k是多少

但我們可以列舉乙個limit for 1->w ,σ(val(rank.k)>=lim的連通塊的個數)就等於答案

為什麼呢,因為這樣乙個連通塊就被統計了val(rank.k)次。

剩下的進行樹形dp,設dp[i][j]為以i為根的子樹,選出j個權值》=limit的點的方案數。

那麼最後統計答案的時候便是σ(dp[i][j])(k<=j<=size(i))

複雜度n^3其實是不對的,但是卡一卡常數還是過得去的

**:

#include#include

#include

#include

#include

#include

#include

#include

#include

#define rg register int

#define rep(i,a,b) for(rg i=a;i<=b;++i)

#define per(i,a,b) for(rg i=a;i>=b;--i)

#define ll long long

#define inf (1<<29)

#define maxn 2000

#define add(x,y) e[++cnt].v=y,e[cnt].next=head[x],head[x]=cnt

using

namespace

std;

intn,m,cnt,w;

intss[maxn],isn[maxn],head[maxn];

ll lim,ans;

ll val[maxn],dp[maxn][maxn],sz[maxn];

//dp[i][j] 在以i為根的子樹,選擇了j個權值大於等於lim的點的方案數

const ll mo=64123

;struct

ee[maxn

<<1

];inline

intread()

while(c>='

0'&&c<='9')

return x*f;

}inline

int mo(int x,int v)

void dfs(int u,int

fa) rep(i,m,sz[u]) ans=mo(ans,dp[u][i]);

}int

main()

cout

<

return0;

}

九省聯考 秘密襲擊

剛開始看起來像樹形dp,卻感覺無從下手 其實正解是fft 每個值的排名往上回溯時都會改變,後效性滿滿的。根本不是一次樹形dp能解決的。那麼,每個值對其他值的排名有什麼影響呢?我們發現只有比val i 大的值才會影響它的排名。不妨每次取乙個點出來,令值大於改點的值變為1,小於改點的值變為0,問題就轉化...

九省聯考 2018 秘密襲擊

題意 給定一顆含 n 個結點的樹,每個點有點權 d i 求所有聯通塊中第 k 大之和。1 leq n,m,k leq 1666,1 leq d i leq m 時間限制 5 秒。題解一道很有趣的題目。做法簡述 由於 dp 為卷積形式對其多項式求點值,並通過類似整體 dp 的方式維護變換,再通過拉格朗...

題解 九省聯考 2018 秘密襲擊 coat

可以將危險程度轉化為 列舉權值 t in 1,w 如果某個連通塊權值不小於 t 的節點個數不小於 k 個那麼造成 1 的貢獻。考慮 dp 令 f 表示以 u 為根子樹中包含 u 的連通塊,有 j 個權值不小於 i 的節點的方案數。轉移就是前兩維列舉,第三維做揹包。不妨令 f z sum limits...