2024.2.16
寄
算是比较难的树形dp了吧。。。
我的跟题解做法不太一样,是维护2个数组
原神
#include <bits/stdc++.h> typedef long long ll; const ll SIZE = 10000 + 100; ll N, M, a[SIZE]; ll C; ll cnt = 1, head[SIZE], next[SIZE * 2], to[SIZE * 2]; ll value[SIZE * 2]; ll key[SIZE]; ll dp[2][SIZE];//dp[0][now] 表示now为中转站的最小花费 dp[1][now] 表示now不为中转站的最小花费 void AddEdge(ll u, ll v, ll w) { ++ cnt; next[cnt] = head[u]; head[u] = cnt; to[cnt] = v; value[cnt] = w; } ll fat[SIZE]; ll f[2][SIZE];//f[0][now] 表示从儿子来的最小花费 f[1][now] 表示从父亲来的最小花费 void Dfs1(ll now, ll fa, ll dis) { ll sum = 0; f[0][now] = 0; for (ll i = head[now]; i; i = next[i]) { if (to[i] == fa) continue; Dfs1(to[i], now, dis + value[i]); sum += f[0][to[i]]; } f[0][now] = std::min(sum + dis * key[now], std::min(dp[0][now], dp[1][now])); } std::pair<ll, ll> no; ll temp[SIZE]; void Dfs3(ll now, ll fa, ll dis) { ll sum = 0; temp[now] = 0; for (ll i = head[now]; i; i = next[i]) { if (to[i] == fa || to[i] == no.first || to[i] == no.second) continue; Dfs3(to[i], now, dis + value[i]); sum += temp[to[i]]; } temp[now] = std::min(sum + dis * key[now], std::min(dp[0][now], dp[1][now])); } void Dfs2(ll now, ll fa, ll dis, ll from) { Dfs3(from, fat[from], dis); f[1][now] += temp[from]; dp[0][from] = std::min(dp[0][from], f[1][now] + dp[1][now]); for (ll i = head[now]; i; i = next[i]) { if (to[i] == fa) continue; Dfs2(to[i], now, dis + value[i], from); } return; } void Dfs(ll now, ll fa) { ll tot = 0; dp[0][now] = dp[1][now] = 1e18; fat[now] = fa; for (ll i = head[now]; i; i = next[i]) { if (to[i] == fa) continue; tot ++; Dfs(to[i], now); } if (!tot) { dp[1][now] = C; return; } else { Dfs1(now, fa, 0); dp[1][now] = f[0][now] + C; } no.first = fa; for (ll i = head[now]; i; i = next[i]) { if (to[i] == fa) continue; no.second = to[i]; Dfs2(to[i], now, value[i], now); } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); freopen("post.in", "r", stdin); freopen("post.out", "w", stdout); std::cin >> N >> M >> C; for (ll i = 1, u, v, w; i < N; ++ i) { std::cin >> u >> v >> w; AddEdge(u, v, w); AddEdge(v, u, w); } for (ll i = 1; i <= M; ++ i) { std::cin >> a[i]; key[a[i]] ++; } Dfs(1, 0); std::cout << std::min(dp[0][1], dp[1][1]) << '\n'; return 0; }
摆
不会行列式和杜教筛
润
这个题好啊,我西索一下。
先知道一个性质:在分治过程中,每一层的长度只有两种可能。可以用归纳证一下。
我们先考虑单独特殊情况:选出的数是2的次幂(如:
那么我们的分治过程如下图:
那我们这个时候如果给
那么就成了下图:
继续加一
有没有发现一些规律???
我们先设每一层原本的二进制长度为
那么对于一个数
然后用线段树维护就行了。
崩坏:星穹铁道
#include <bits/stdc++.h> typedef long long ll; const int SIZE = 1e5 + 100; const int mod = 998244353; class Node { public: int l, r; ll sum[2]; int first[2]; }; int N, M; int s[SIZE]; ll power2[SIZE]; class SegmentTree { #define lid (id << 1) #define rid (id << 1 | 1) public: int tag[SIZE * 4]; Node node[SIZE * 4]; private: Node pushup(Node lson, Node rson) { Node result; result.l = lson.l; result.r = rson.r; result.first[0] = std::min(lson.first[0], rson.first[0]); result.first[1] = std::min(lson.first[1], rson.first[1]); result.sum[0] = (lson.sum[0] * power2[rson.r - rson.l + 1] % mod + rson.sum[0]) % mod; result.sum[1] = (lson.sum[1] * power2[rson.r - rson.l + 1] % mod + rson.sum[1]) % mod; return result; } void Zero(Node &a) { a.first[0] = 1e9; a.sum[0] = 0; a.first[1] = a.l; a.sum[1] = (power2[a.r - a.l + 1] - 1 + mod) % mod; } void One(Node &a) { a.first[0] = a.l; a.sum[0] = (power2[a.r - a.l + 1] - 1 + mod) % mod; a.first[1] = 1e9; a.sum[1] = 0; } void Swap(Node &a) { std::swap(a.first[0], a.first[1]); std::swap(a.sum[0], a.sum[1]); } void Cover(int id, int New) { if (New == 1) { if (tag[id] == 2) One(node[id]), New = 3; else if (tag[id] == 3) Zero(node[id]), New = 2; else { Swap(node[id]); if (tag[id]) New = 0; } } else { if (New == 2) Zero(node[id]); else One(node[id]); } tag[id] = New; } void pushdown(int id) { if (tag[id] == 0) return; Cover(lid, tag[id]); Cover(rid, tag[id]); tag[id] = 0; } public: void build(int id, int l, int r) { if (l == r) { if (s[l] == 1) { node[id].first[0] = l; node[id].first[1] = 1e9; node[id].sum[0] = 1; node[id].sum[1] = 0; } else { node[id].first[0] = 1e9; node[id].first[1] = l; node[id].sum[0] = 0; node[id].sum[1] = 1; } node[id].l = node[id].r = l; return; } int mid = (l + r) >> 1; build(lid, l, mid); build(rid, mid + 1, r); node[id] = pushup(node[lid], node[rid]); return; } void Update(int id, int l, int r, int askL, int askR, int flag) { if (askL <= l && r <= askR) { Cover(id, flag); return; } int mid = (l + r) >> 1; pushdown(id); if (askL <= mid) Update(lid, l, mid, askL, askR, flag); if (mid + 1 <= askR) Update(rid, mid + 1, r, askL, askR, flag); node[id] = pushup(node[lid], node[rid]); } Node Query(int id, int l, int r, int askL, int askR) { if (askL <= l && r <= askR) return node[id]; int mid = (l + r) >> 1; pushdown(id); Node result; result.l = result.r = result.first[0] = result.first[1] = 1e9; result.sum[0] = result.sum[1] = 0; if (askL <= mid) { result = Query(lid, l, mid, askL, askR); } if (mid + 1 <= askR) { if (result.l == 1e9) result = Query(rid, mid + 1, r, askL, askR); else result = pushup(result, Query(rid, mid + 1, r, askL, askR)); } return result; } #undef lid #undef rid }tree; std::string str; ll treeSum[SIZE], prefix[SIZE], powerSum[SIZE]; int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); freopen("run.in", "r", stdin); freopen("run.out", "w", stdout); std::cin >> N >> M; power2[0] = 1; for (int i = 1; i <= N; ++ i) { power2[i] = power2[i - 1] * 2 % mod; treeSum[i] = (treeSum[i - 1] * 2 % mod + (1 + i - 1) * power2[i - 1] % mod) % mod; powerSum[i] = (powerSum[i - 1] + power2[i - 1]) % mod; prefix[i] = (prefix[i - 1] + power2[i - 1] * (1 + i - 1)) % mod; } std::cin >> str; std::reverse(str.begin(), str.end()); for (int i = 1; i <= N; ++ i) { s[i] = str[i - 1] - '0'; } tree.build(1, 1, N); for (int i = 1, opt, l, r; i <= M; ++ i) { std::cin >> opt >> l >> r; l = N - l + 1; r = N - r + 1; std::swap(l, r); if (opt == 4) { Node first = tree.Query(1, 1, N, l, r); if (first.first[0] == 1e9) { std::cout << 0 << '\n'; continue; } ll answer = treeSum[first.r - first.first[0] + 1]; Node second = tree.Query(1, 1, N, first.first[0] + 1, r); if (second.first[0] == 1e9) { std::cout << answer << '\n'; continue; } ll val = second.sum[0]; ll len1 = first.r - first.first[0] + 1; ll len2 = first.r - second.first[0] + 1; ll temp = power2[len1 - 1] * (len1 + len1 - len2 + 1) % mod * (len2) % mod * 499122177 % mod; temp = (temp + prefix[len1 - len2] * val % mod) % mod; answer = (answer - temp + mod) % mod; temp = (temp + power2[len1 - 1] * len2 % mod) % mod; temp = (temp + powerSum[len1 - len2] * val % mod) % mod * 2 % mod; answer = (answer + temp) % mod; answer = (answer + 2 * val) % mod; std::cout << answer << '\n'; } else { tree.Update(1, 1, N, l, r, opt); } } return 0; } /* 5 1 01010 4 2 5 */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2023-02-17 P4035 [JSOI2008]球形空间产生器