HNOI2015實驗比較 樹型DP

2021-08-16 21:54:31 字數 3871 閱讀 9553

我看了一下,網上好像沒有跟我一樣做法的,而且我根本學不會那個做法。那我只好發個部落格啦(做法也許有錯)!有n

n

個物品和

m' role="presentation" style="position: relative;">m

m個條件,每個條件表示

i i

的權值小於或等於

j' role="presentation" style="position: relative;">j

j的權值,每個

j j

只會出現一次。

要求給每個物品分配乙個權值,使得滿足所有的條件,並且

1' role="presentation" style="position: relative;">11到

max max

的每個值都出現了(其中ma

x max

指最大權值)。首先i

=ji =j

的條件很好搞,直接用個並查集合並就行了。

然後每個

j j

只會出現一次,所以就可以把

i' role="presentation" style="position: relative;">i

i當做其父親。

如果出現了環,就一定沒有滿足條件的方案。

那麼原問題可以轉化為:一棵森林,給每個點分配乙個權值,使得

1、每個點的權值比父親大; 2、1

1

到max' role="presentation" style="position: relative;">max

max的每個值都出現了。

為了方便,可以算每個點權值比父親小,意義是一樣的。 設d

p[i]

[j] dp[

i][j

]為考慮了

i i

這棵子樹,

i' role="presentation" style="position: relative;">i

i的權值不大於

j j

時的方案數,那麼不考慮2條件,那麼dp

[i][

j]=d

p[i]

[j−1

]+∏u

is a so

n of

idp[u][

j−1]

' role="presentation">dp[

i][j

]=dp

[i][

j−1]

+∏ui

saso

nofi

dp[u

][j−

1]dp

[i][

j]=d

p[i]

[j−1

]+∏u

isas

onof

idp[

u][j

−1]設

dp[0

][j]

d p[

0][j

]為考慮所有點,最大權值為

j j

時的方案數,則dp

[0][

i]=∏

u is

a rootd

p[u]

[j]' role="presentation">dp[

0][i

]=∏u

isar

ootd

p[u]

[j]d

p[0]

[i]=

∏uis

aroo

tdp[

u][j

]接下來考慮2條件。設f[

i]f [i

]為最大值為

i i

並且每個值都出現了的方案數。可以得到f[

i]=d

p[0]

[i]−

∑j=1

i−1f

[j]∗

cij' role="presentation">f[i

]=dp

[0][

i]−∑

j=1i

−1f[

j]∗c

jif[

i]=d

p[0]

[i]−

∑j=1

i−1f

[j]∗

cij那麼

∑f[i

] ∑f[

i]

就是答案了。

時間複雜度:o(

n2) o(n

2)

#include

using

namespace

std;

#define rep(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i<=i##end;++i)

#define drep(i,st,ed) for(int i=(int)(st),i##end=(int)(ed);i>=i##end;--i)

template

bool chkmin(t &x,const t &y)

template

bool chkmax(t &x,const t &y)

#ifdef __linux__

#define getchar getchar_unlocked

#define putchar putchar_unlocked

#endif

template

t read()

while((c>='0')&&(c<='9'))x=(x<<1)+(x<<3)+(c^48),c=getchar();

return x*f;

}#define read() read()

template

void write(t x,char c)

#define pb push_back

typedef

long

long ll;

typedef

double lf;

const

int maxn=105,mod=1e9+7;

int n,m,tot;

int fa[maxn],id[maxn];

int c[maxn][maxn];

void add(int &x,const

int &y)

void init()

int find_fa(int x)

bool p[maxn][maxn],p2[maxn][maxn],indeg[maxn];

int lim,dp[maxn][maxn],f[maxn],vis_cnt;

vector

e[maxn];

void dfs(int u)

if(u>0)

add(dp[u][i],dp[u][i-1]);

}}int main()

rep(i,1,n)

if(fa[i]==i)

id[i]=++tot;

rep(i,1,n)

if(fa[i]!=i)

id[i]=id[find_fa(i)];

rep(i,1,n)

rep(j,1,n)

if(p[i][j])

rep(i,1,tot)

rep(j,1,tot)

if(p2[i][j])

e[i].pb(j);

rep(i,1,tot)

if(!indeg[i])

e[0].pb(i);

dfs(0);

int ans=0;

rep(i,1,tot)

write(vis_cnt==tot?ans:0,'\n');

return

0;}

HNOI2015 實驗比較

description input output sample input 5 4 1 2 1 3 2 4 1 5 sample output 5data constraint 首先對於給出的等於條件,我們可以直接把點合併。對於合併後的圖,我們發現要麼是環,要麼是樹,環則直接無解,樹我們可以用樹形d...

HNOI2015 實驗比較

description input output sample input 5 4 1 2 1 3 2 4 1 5 sample output 5data constraint 首先對於給出的等於條件,我們可以直接把點合併。對於合併後的圖,我們發現要麼是環,要麼是樹,環則直接無解,樹我們可以用樹形d...

HNOI2015實驗比較 題解

記得幾個月前自己曾經做過一道關於一張dag求排列的問題,現如今遇到了的是一道關於樹求排列的問題.這乙個問題看似簡單實際上有乙個細節那就是他可以取 這就使得複雜度公升高了.首先,最簡單的插孔原理。這乙個非常簡單,做這道題時,蒟蒻我現推式子。為什麼要解決這個問題呢,因為最基本的,在不考慮等於的情況下,n...