省選模擬 19 09 11

2021-09-27 03:32:39 字數 3277 閱讀 1264

ps. 博主趁資訊課摸魚考的暴零模擬

看門人憑感覺就知道是長鏈剖分,將路徑查分一下,dis

u+di

sv−2

∗dis

lc

adis_u+dis_v-2*dis_

disu​+

disv

​−2∗

disl

ca​維護fu,

if_

fu,i

​表示u的子樹,深度為 i 的點的 dis

disdi

s最大值

考慮如何合併長鏈

列舉一條長鏈,在另一邊的長鏈上對應一段區間,可以用線段樹查詢一下區間的最大dis

disdi

s然後合併的時候需支援單點取 max

maxma

x ,類似重鏈,長鏈剖分也可以有dfs

dfsdf

s序,就是先 dfs

dfsdf

s 長兒子就可以了

#include#define n 1000050

using namespace std;

int read()

while(isdigit(ch)) cnt = (cnt << 1) + (cnt << 3) + (ch-'0'), ch = getchar();

return cnt * f;

}typedef long long ll;

const int mod = 998244353;

ll add(ll a, ll b)

ll mul(ll a, ll b)

int first[n], nxt[n], to[n], w[n], tot;

void adde(int x, int y, int z)

int n, l[n], r[n];

int len[n], son[n], in[n], pos[n], sign;

ll ans[n], dis[n];

void dfs(int u) if(typ) len[u] = len[son[u]] + 1;

}void dfs2(int u)

ll mx[n<<2];

void pushup(int x)

void build(int x, int l, int r)

int mid = (l+r) >> 1;

build(x<<1, l, mid); build(x<<1|1, mid+1, r);

pushup(x);

}void upt(int x, int l, int r, int pos, ll v)

ll query(int x, int l, int r, int l, int r)

void dfs3(int u)

for(int i = 1; i <= len[t]+1; i++) upt(1, 1, n, in[u] + i, query(1, 1, n, in[t] + i - 1, in[t] + i - 1)); }}

int main()

dfs(1); dfs2(1); build(1, 1, n); dfs3(1);

ll tmp = 1, sum = 0;

for(int i = n; i >= 1; i--) cout << sum; return 0;

}

仙人球

如果是樹的話就是乙個簡單的揹包…

我們可以把環單獨提出來,定乙個環的根,把乙個環拆成一條鏈出來

然後分別計算不經過環根的與經過環根的

經過環根的一定是兩邊拼起來,強制一邊選到乙個位置,另一邊就是乙個字首和

#include#define n 5050

#define m 105

#define pb push_back

using namespace std;

const int mod = 1e9 + 7;

int read()

while(isdigit(ch)) cnt = (cnt << 1) + (cnt << 3) + (ch-'0'), ch = getchar();

return cnt * f;

}int add(int a, int b)

int mul(int a, int b)

void add(int &a, int b)

vectore[n];

int f[n][m], pre[n][m], suf[n][m];

int dfn[n], sign, bel[n], cnt, isrt[n];

int n, m, k, from[n], vis[n], ans;

vectorv[n];

void tarjan(int u, int fa)

} }}int tmp[m], tmp2[m];

void dp(int *a, int *b, int *c)

void calc(int u)

memcpy(pre[0], f[now[0]], sizeof(pre[0]));

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

memcpy(suf[n], f[now[n]], sizeof(suf[n]));

for(int i = n-1; i >= 0; i--)

memset(tmp, 0, sizeof(tmp));

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

for(int j = 1; j <= k; j++)

add(tmp[j], pre[i][j]);

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

for(int j = 1; j <= k; j++)

add(tmp[j], suf[i][j]);

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

for(int j = 1; j <= k; j++)

add(pre[i][j], pre[i-1][j]);

for(int i = 0; i <= n-2; i++)

dp(tmp, pre[i], suf[i+2]);

dp(f[u], f[u], tmp);

}void dfs(int u)

} if(isrt[u]) calc(u);

for(int i = 1; i <= k; i++) add(ans, f[u][i]);

}int main() tarjan(1, 0);

dfs(1); cout << ans; return 0;

}

省選模擬96

容易發現當 k 3 時無解。然後容易證明當 k 3 時,只有 m 3 才是有解的。然後直接做不好做,考慮欽定然後容斥出合法方案。對於 k 3 列舉乙個點,然後計算另乙個的方案數。其他情況類似,欽定滿足條件的角,然後容斥。然後對於每乙個 o n 的式子用組合恒等式大力化簡就可以做到 o 1 了。考慮每...

省選模擬86

首先考慮基礎的dp定義,那麼發現轉移需要的係數只和dp是奇數的點的個數有關,所以將這個東西記錄在dp狀態中就行了。然後推一下dp轉移,發現轉移係數和奇數的點的個數沒有關係,只與是否存在這樣的點有關,所以用01來記錄就可以了。考慮用總方案減去不合法的方案,也就是1號點能到達的點和2號點能到達的點沒有交...

省選模擬76

發現答案一定可以是一棵樹,因為對於任意乙個合法的圖求出它的最小割樹也是答案。然後就考慮構造,根據一些性質可以猜想實際上就是原圖的最大生成樹,所以直接跑就行了。求出生成樹之後再暴力檢驗是否合法即可。發現這個東西的形式很熟悉,假如再加入第乙個點和最後乙個點的權值的話,那麼答案就是虛樹邊權和的二倍。那麼現...