正睿2020提高組十連測 選做

2022-03-12 12:19:34 字數 3882 閱讀 6503

更新中...

目錄題目鏈結

理解題意,打出第乙個暴力

首先需要知道,隨機生成的樹(如果不特別說明隨機方法,就是指在所有\(n^\)棵樹里隨機),最大深度期望是\(o(\sqrt)\)的。

看本題。首先,期望是嚇唬你的,因為期望乘上階乘,其實就是求和。於是我們要求【所有排列下【操作後所有點的權值和】的和】。因此暴力做法就是列舉乙個排列,模擬操作,時間複雜度\(o(n!\cdot \text(n))\)。值得一提的是,操作時,枚舉子樹里所有的點,可以通過\(\text\)序實現不重不漏的列舉,比較優美。

深度對應係數,從樹上問題到序列問題

繼續優化。首先發現,乙個點\(u\)的權值\(a_u\),在完成所有操作後,能貢獻到另乙個點\(v\)的權值上,當且僅當\(u\)是\(v\)的祖先(其實這裡強調的是必要性。充分性你可以理解為貢獻為\(0\)也是貢獻)。於是我們列舉每一對這樣的\(u,v\)。考慮\(u,v\)的距離,也就是深度差。發現當深度差相等時,\(u\)對\(v\)貢獻的係數是一樣的!

具體來說,假設\(u,v\)之間的路徑上,共有\(d\)個點(含\(u\)和\(v\))。我們預處理出乙個係數\(f_d\)。則答案就是:

\[\sum_v\\d=\text[v]-\text[u]+1}}a_u\times f_d\times \times(n-d)!

\]其中\(\times (n-d)!\)是因為,除\(u,v\)路徑以外的點,不會影響\(u\)對\(v\)的貢獻,所以可以任意排列。

考慮預處理出\(f_d\)。先看是什麼,再看怎麼求。\(f_d\)是什麼呢?可以考慮乙個長度為\(d\)的序列\(x_1,x_2,\dots ,x_d\),初始時等於\(1,0,0,\dots 0\)。我們列舉\(d!\)個排列,對每個排列\(p_1,p_2,\dots ,p_d\),依次對每個位置\(p_i\),把\(x_,x_,\dots ,x_\)加上\(x_\)。把每個排列下,最後得到的\(x_d\)的值加起來,就是\(f_d\)了。

也就是說,樸素求\(f_d\)的複雜度是\(d!\)的。因為\(d\leq \text=o(\sqrt)\),所以暴力預處理的複雜度\(o((\sqrt)!\cdot \text(\sqrt))\)。也可以改成狀壓dp。都能比\(n!\)純暴力多拿一些分。

遞推求出係數

考慮遞推求\(f_}\)。特別地,我們定義\(f_1=1\)。可能有人會認為\(f_1=2\)(因為題目說了,子樹加的時候包括自己)。但遞推時,我們只考慮第乙個點對最後乙個點貢獻了多少,既然是貢獻就不算它原本自己有的乙份。不過這樣在上面求答案的那個式子裡,可能\(u=v\)時就要特判一下了。

從\(f_\)遞推到\(f_d\)時,考慮在\(1\)之後被操作到的點有幾個。也就是說,假設排列裡\(p_t=1\),那麼在\(1\)之後被操作到的點就有\(d-t\)個,設\(i=d-t\),列舉\(i\) (\(0\leq i)。得到如下遞推式:

\[f_d=\sum_^(d-i-1)!\left(i!+\sum_^f_j(i-j)!\right)

\]解釋一下這個式子:

顯然,在操作到\(1\)之前,前面的操作都是無效的。因為它們的初始值都是\(0\)。這些東西可以任意排列,並且要選出哪幾個位置排在\(1\)之前,於是乘上係數\((d-i-1)!\)。

接下來只考慮後\(i\)個被操作的點,它們的不同排列順序下,產生的貢獻之和。

操作到\(1\)時,會令\(x_2\dots x_d\)全部變成\(1\)。那麼在所有情況下,\(1\)對\(x_d\)會先有乙個\(i!\)的貢獻(因為後面的數有這麼多種排列方式,每次的貢獻都是\(1\))。

接下來,會依次對\(i\)個數進行操作,且它們初始值都是\(1\)。可以再用一次算貢獻的思想,分別計算這\(i\)個\(1\)的貢獻,那麼就是\(f_1+f_2+\dots +f_i\)。其中 \(f_j\) 是離 \(x_d\) 第 \(j\) 近的、未被操作過的位置。對於每個 \(j\),\(f_j\) 裡已經包含了它和它後面的數(以位置來說的「後面」)的所有排列方式,但它前面的、未被操作過的數,可以按任意順序操作(\((i - j)!\) 種操作順序)。並且前後兩部分之間互不影響,各自確定了順序後可以穿插在一起(\(\) 種穿插情況)。

定義:\[g_i=\sum_^f_j(i-j)!

\]則:

\[f_d=\sum_^(d-i-1)!(i!+g_i)

\]每算出來乙個\(f_d\)就更新一下它對\(g_\)的貢獻即可。

時間複雜度\(o(n)\)。

//problem:zr1534

#include using namespace std;

#define pb push_back

#define mk make_pair

#define lob lower_bound

#define upb upper_bound

#define fi first

#define se second

#define sz(x) ((int)(x).size())

typedef unsigned int uint;

typedef long long ll;

typedef unsigned long long ull;

typedef pairpii;

templateinline void ckmax(t& x,t y)

templateinline void ckmin(t& x,t y)return y;}

int fac[maxn+5],ifac[maxn+5];

inline int comb(int n,int k)

int n,a[maxn+5];

struct edgeedge[maxn*2+5];

int head[maxn+5],tot;

inline void add_edge(int u,int v)

int dep[maxn+5],dfn[maxn+5],ofn[maxn+5],rev[maxn+5],cnt_dfn;

void dfs(int u,int fa)

ofn[u]=cnt_dfn;

}int f[maxn+5],g[maxn+5];

int main()

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

cin>>a[i];

dfs(1,0);

int maxd=0;

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

ckmax(maxd,dep[i]+1);

f[1]=1;

for(int i=1;i題目鏈結

結論:\(m>0\) 時,答案一定是 \(\text\)。證明如下:

將每條邊定向:從編號較小的點,連向編號較大的點。那麼會得到乙個 dag。

按拓撲序確定每個點的顏色(\(0\) 或 \(1\),分別代表工業城市/農業城市)。初始時,我們讓入度為 \(0\) 的點,顏色全部為 \(0\)。

考慮其它任意一點 \(u\) 的入邊。假設有 \(x\) 條邊來自 \(0\), \(y\) 條邊來自 \(1\):

那麼可以保證,任意一點 \(u\) 的所有入邊裡,兩端顏色不同的邊數 \(\geq\) 兩端顏色相同的邊數。當且僅當 \(x=y\) 時取等號。

通過考慮每個點的入邊,我們不重不漏地考慮到了所有的邊。因此,現在可以保證整張圖里,兩端顏色不同的邊數 \(\geq\) 兩端顏色相同的邊數。並且只要存在乙個點,它的 \(x\neq y\),整張圖就能取大於號。

因為初始時,我們讓入度為 \(0\) 的點全部染了相同的顏色,所以發現所有「第二層」的點,一定是:\(x>0,y=0\)。因此存在 \(x>y\) 的點,即整張圖里 兩端顏色不同的邊數 \(>\) 兩端顏色相同的邊數。

#include int main()

正睿 2018 提高組十連測 Day5

鴨血居然沒想到字首和優化dp,主要是寫的是刷表.只想到線段樹優化,還要兩棵.首先是暴力解法 f i j f i 1 k 0 k j 2 嗯.這個顯然可以字首和優化.然後是正常人dp解法 令f i,j 表示長度為i總和為j的合法陣列個數 則f i j f i j 1 f i 1 j 2 第二項只有j為...

2019正睿CSP S模擬賽十連測day8

link to this contest 這場題做的體驗一般,沒有 探索中求進步 的思考快感,會做的直接做,不會做的一點思路都沒有,晚了半個小時開始,提早乙個小時結束操作 t1 轉化以下題意直接模擬,t2 完全不會,去看 t3 看來看去都只會 50 的部分分,感覺也不少了就寫完放棄了,回去把 t2 ...

BFS BZOJ省選十連測 Cycle

蛤?這題絕對有問題。複雜度明顯不對頭。它的想法其實就是找到乙個點,判斷它與它周圍的點能否構成環,然後不能再刪去這個點。然而。他每次都memset了一發,這不t?服都服了。include include include include define sf scanf define pf printf ...