HNOI2015實驗比較 題解

2021-08-23 14:07:13 字數 3080 閱讀 6558

記得幾個月前自己曾經做過一道關於一張dag求排列的問題,現如今遇到了的是一道關於樹求排列的問題.

這乙個問題看似簡單實際上有乙個細節那就是他可以取=。

這就使得複雜度公升高了.

首先,最簡單的插孔原理。這乙個非常簡單,做這道題時,蒟蒻我現推式子。

為什麼要解決這個問題呢,因為最基本的,在不考慮等於的情況下,n個數插入m個數的空隙中就相當於題目中的把兩組不等式合起來.

怎麼推?

設序列a,b

由於發現合併後的序列c中,原本的關係順序不能改變,也就是a1仍然在a2前面,a2仍然在a3前面,所以a1如果插入了乙個位置,那麼a2只能插a1後面的位置.

這個時候暴力搞法就是插入ai時列舉ai-1在哪個位置。但不妨這樣想,先不考慮位置變化的情況,也就是預設a2可以在a1前面,那麼這樣的插入情況就是:

原本有m個孔,然後插入乙個以後,就會變成m+1個孔,因為會新增插入的那個數左右兩邊的孔,這樣的情況是(m+1)×(m+2)×…..×(m+n).

然後把這樣的情況除以乙個n的排列,就能保證a1在a2前面了.

所以式子變成 πn

i=1(

m+i)

n!π i=

1n(m

+i)n

!如果我麼給上下同時乘上乙個m!

m

!那麼就會有(m

+n)!

n!×m

! (m+

n)!n

!×m!

顯然乙個組合數.

換一種理解實際上就是合併後有m+n個數,這m+n個數中隨意挑選n個位置作為f放a序列的,然後剩下的m個位置放b序列.

接著考慮有等號的情況。我們發現如果是乙個序列裡有等號,那麼等號左右兩邊的相當於是乙個數,然後就可以把他們縮在一起,這樣等號就被消掉了。

我們如果想讓兩個沒有等號的序列合在一起變成有等號的怎麼辦?

我們發現如果ai要等與bj,那麼ai的考慮可以插入的孔就會減少,因為他不能插在兩個數中間,只能插在乙個數上面,而且那個數只能允許他乙個人插.

這樣的理解實在沒有什麼好的進展。但我們知道如果列舉合併後有多少個等號就可以了。也就是說長度為n的a序列,m的b序列合併成p的c序列.

顯然的,可以確定p > n, p > m,p < m + n;

然後,還是在p個位置中選出n個放a序列,這時,剩下的位置已經不足以放b序列,但是可以在已經放好a序列的位置裡選出m+n-p個位置放b序列,所以說,方案數為 cn

p×cp

−m−n

n cpn

×cnp

−m−n

可以看出,開頭提及的只是一種特殊情況。

#include

using

namespace

std;

template

inline

void read(t&data)

return;

}const

int _ =101;

const

int mod = 1e9+7;

int n,m;

int c[_<<1][_<<1],cnt,parent[_],to[_<<1],nxt[_],head[_],degree1[_],degree2[_],size[_],dp[_][_],g[_],dp[_];

bool vis[_];

struct relpo[_];

inline

int poww(register

int x,register

int y)

return ret;

}inline

int getni(register

int x)

inline

void init()

}}inline

void add(register

int a,register

int b)

inline

int fi(register

int x)

void dfs(register

int now)

size[now]+=size[to[i]];

continue;

}for(register

int j=size[now]+size[to[i]];j>=1;--j)g[j]=0;

for(register

int j=size[to[i]];j>=1;--j)}}

size[now]+=size[to[i]];

for(register

int j=size[now];j>=1;--j)dp[now][j]=g[j];

}if(size[now]==0)

for(register

int i=size[now];i>=0;--i)dp[now][i+1]=dp[now][i];size[now]++;

return;

}int main()

else

po[++cc].fa=a,po[cc].son=b;

}for(register

int i=1;i<=cc;++i)

add(fi(po[i].fa),fi(po[i].son)),++degree1[fi(po[i].fa)],++degree2[fi(po[i].son)];

register

int ans=0,sz=0;

for(register

int i=1;i<=n;++i)

sz+=size[qio];

continue;

}for(register

int j=sz+size[qio];j>=1;--j)g[j]=0;

for(register

int j=size[qio];j>=1;--j)}}

sz+=size[qio];

for(register

int j=sz;j>=1;--j)

dp[j]=g[j]; }}

for(register

int i=1;i<=n;++i)

printf("%d",ans);

}

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 開店 題解

目前只有開o2能過,stl的常數太大了,qwq 題意簡述,給你一棵樹,有點權與邊權,然後有很多詢問,每次詢問你點權在l r l r範圍內的點到給點點v v的距離之和。我們使用動態點分治來求取答案。先構建出點分樹,樹高肯定是在log nlog n級別內的,然後對於乙個分治點 重心 我們在上面記錄三個值...