記得幾個月前自己曾經做過一道關於一張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級別內的,然後對於乙個分治點 重心 我們在上面記錄三個值...