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