20250204

T1

分糖果

考虑链,只需要线段树维护 dp 转移。考虑环,然后容斥,钦定最后一个人和第一个人一样。这样就相当于把最后一个人去掉,把第一个人的 \(a_i = \min \{a_i, a+n\}\),然后再做环上的问题。因此先把最小的人循环移位到第一个,这样容斥一直做下去就方便很多。最后相当于是所有前 \(i\) 个人的答案乘以 \(\pm 1\) 加起来。不能动开,要离散化。线段树区间归零、区间取反最好做成区间乘法,这样方便且常数小。

代码
#include <iostream>
#include <algorithm>
#include <time.h>
#define int long long
using namespace std;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
char buf[1<<21],*p1,*p2,ch;
int read(){int ret=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')ret=ret*10+c-'0',c=getchar();return ret;
}
const int P = 1000000007;
inline void Madd(int& x, int y) { (x += y) >= P ? (x -= P) : 0; }
int n, mp;
int a[2000005], v[2000005];
struct Segment_Tree {int s[4000005], tga[4000005], tgm[4000005];int sv[4000005];inline void taga(int o, int v) {s[o] = (s[o] + sv[o] * v) % P;Madd(tga[o], v);}inline void tagm(int o, int v) {tga[o] = tga[o] * v % P;tgm[o] = tgm[o] * v % P;s[o] = s[o] * v % P;}void pushdown(int o) {if (tgm[o] != 1) {tagm(o << 1, tgm[o]);tagm(o << 1 | 1, tgm[o]);tgm[o] = 1;}if (tga[o] != 0) {taga(o << 1, tga[o]);taga(o << 1 | 1, tga[o]);tga[o] = 0;}}inline void pushup(int o) { s[o] = (s[o << 1] + s[o << 1 | 1]) % P; }void Build(int o, int l, int r) {tgm[o] = 1;if (l == r) {sv[o] = v[l];return;}int mid = (l + r) >> 1;Build(o << 1, l, mid);Build(o << 1 | 1, mid + 1, r);sv[o] = sv[o << 1] + sv[o << 1 | 1];}void Add(int o, int l, int r, int L, int R, int v) {if (L <= l && r <= R) return taga(o, v);pushdown(o);int mid = (l + r) >> 1;if (L <= mid) Add(o << 1, l, mid, L, R, v);if (R > mid) Add(o << 1 | 1, mid + 1, r, L, R, v);pushup(o);}void Mul(int o, int l, int r, int L, int R, int v) {if (L <= l && r <= R) return tagm(o, v);pushdown(o);int mid = (l + r) >> 1;if (L <= mid) Mul(o << 1, l, mid, L, R, v);if (R > mid) Mul(o << 1 | 1, mid + 1, r, L, R, v);pushup(o);}int Query() { return s[1]; }void dfs(int o, int l, int r) {if (l == r) {cout << s[o] << " ";return;}pushdown(o);int mid = (l + r) >> 1;dfs(o << 1, l, mid);dfs(o << 1 | 1, mid + 1, r);}
} seg;
int d[1000005], dcnt;
signed main() {// int ttt = clock();freopen("candy.in", "r", stdin);freopen("candy.out", "w", stdout);n = read();for (int i = 1; i <= n; i++) a[i] = read(), d[i] = a[i], a[i + n] = a[i];sort(d + 1, d + n + 1);dcnt = unique(d + 1, d + n + 1) - d - 1;for (int i = 1; i <= dcnt; i++) v[i] = d[i] - d[i - 1];seg.Build(1, 1, dcnt);for (int i = 1; i <= n; i++) {if (!mp || a[i] < a[mp]) mp = i;}a[mp] = lower_bound(d + 1, d + dcnt + 1, a[mp]) - d;seg.Add(1, 1, dcnt, 1, a[mp], 1);int ans = 0;for (int i = mp + 1, s = seg.Query(); i < mp + n; i++) {// seg.dfs(1, 1, dcnt);// cout << "\n";a[i] = lower_bound(d + 1, d + dcnt + 1, a[i]) - d;if (a[i] < dcnt) seg.Mul(1, 1, dcnt, a[i] + 1, dcnt, 0);seg.Mul(1, 1, dcnt, 1, dcnt, P - 1);seg.Add(1, 1, dcnt, 1, a[i], s);s = seg.Query();if ((mp + n - i) & 1) ans += s;else ans -= s;ans = (ans + P) % P;// seg.dfs(1, 1, dcnt);// cout << "\n";}cout << ans << "\n";// cerr << (1.0 * clock() - ttt) / CLOCKS_PER_SEC << "\n";return 0;
}

T2

光明

首先 \(f(u, i)\) 即为 \(u\) 子树内距离 \(u\) 深度为 \(i\) 的点个数。然后注意到对于每一个深度,它对上面的 \(u\) 的贡献是 \(u\) 深度越浅就越大的。再观察一下就会发现这个深度对于其上面的 \(u\) 的本质不同贡献只有 \(O(该深度点个数)\) 种,也就是这些点虚树上每一条边内部的点。于是总共来说本质不同的 \(f(u, i)\) 就是 \(O(n)\) 级别,可以直接全搞出来排序做。

代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
char buf[1<<21],*p1,*p2,ch;
long long read(){long long ret=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')ret=ret*10+c-'0',c=getchar();return ret;
}
int head[3000005], nxt[3000005], to[3000005], ecnt;
void add(int u, int v) { to[++ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt; }
int fa[3000005], dfn[3000005], _dfn[3000005], dep[3000005], ncnt;
int sz[3000005], son[3000005], top[3000005];
vector<int> vec[3000005];
void dfs1(int x, int d) {sz[x] = 1;dep[x] = d;_dfn[dfn[x] = ++ncnt] = x;for (int i = head[x]; i; i = nxt[i]) {int v = to[i];if (v != fa[i]) {dfs1(v, d + 1);sz[x] += sz[v];if (sz[v] > sz[son[x]]) son[x] = v;}}
}
void dfs2(int x, int t) {top[x] = t;if (son[x]) dfs2(son[x], t);for (int i = head[x]; i; i = nxt[i]) {int v = to[i];if (v != son[x] && v != fa[x]) dfs2(v, v);}
}
int LCA(int x, int y) {while (top[x] ^ top[y]) (dep[top[x]] < dep[top[y]]) ? (y = fa[top[y]]) : (x = fa[top[x]]);return (dep[x] < dep[y] ? x : y);
}
int n;
long long K;
int vsz[3000005];
struct node {int v, cnt;
};
vector<node> ans;
int stk[3000005], ssz;
void work(vector<int>& key) {int kcnt = key.size();stk[ssz = 1] = 1;vsz[1] = (key[0] == 1);for (int i = (key[0] == 1); i < kcnt; i++) {int t = LCA(stk[ssz], key[i]);vsz[key[i]] = 1;if (stk[ssz] != t) {while (ssz > 1 && dfn[t] < dfn[stk[ssz - 1]]) {vsz[stk[ssz - 1]] += vsz[stk[ssz]];ans.emplace_back((node) { vsz[stk[ssz]], dep[stk[ssz]] - dep[stk[ssz - 1]] });--ssz;}if (t != stk[ssz - 1]) {vsz[t] = 0;vsz[t] += vsz[stk[ssz]];ans.emplace_back((node) { vsz[stk[ssz]], dep[stk[ssz]] - dep[t] });stk[ssz] = t;} else {vsz[t] += vsz[stk[ssz]];ans.emplace_back((node) { vsz[stk[ssz]], dep[stk[ssz]] - dep[t] });--ssz;}}stk[++ssz] = key[i];}for (int i = ssz; i > 1; i--) vsz[stk[i - 1]] += vsz[stk[i]], ans.emplace_back((node) { vsz[stk[i]], dep[stk[i]] - dep[stk[i - 1]] });ans.emplace_back((node) { vsz[1], 1 });
}
signed main() {freopen("light.in", "r", stdin);freopen("light.out", "w", stdout);n = read(), K = read();for (int i = 2; i <= n; i++) add(fa[i] = read(), i);dfs1(1, 1);dfs2(1, 1);for (int i = 1; i <= n; i++) vec[dep[_dfn[i]]].emplace_back(_dfn[i]);for (int i = 1; i <= n; i++) {if (vec[i].empty()) break;work(vec[i]);}sort(ans.begin(), ans.end(), [](node a, node b) { return a.v > b.v; });long long aans = 0;for (auto v : ans) {if (K <= v.cnt) {aans += 1ll * v.v * K;break;}K -= v.cnt;aans += 1ll * v.v * v.cnt;}cout << aans << "\n";return 0;
}

T3

游戏

\(k\) 大小分开做。\(k\) 小矩乘,\(k\) 大容斥。后面忘了。


线段树操作和标记少一点,维护简单且跑得快。

#define int long long 的时候,快读函数的返回值也要开 ll。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/878821.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CubeMX 生成代码 在VScode 中显示未定义,解决办法

CubeMX 生成代码 在VScode 中显示未定义,解决办法CubeMX 生成代码 在VScode 中显示未定义,解决办法 1. 背景 CubeMX 生成代码 在VScode 中显示未定义,未定义、头文件路径无效,在当实际上是可以编译成功的。 2. 原因 keil软件编译器会预编译一些头文件,vscode没有编译 3. 解…

从《だから僕は音楽を辞めた》到《エルマ》

《エルマ》专辑访谈从《だから僕は音楽を辞めた》到《エルマ》 从专辑制作实况到更深层的乐器与演奏方式的执着,除了n-buna、suis之外,支援ヨルシカ的下鹤光康(吉他)、キタニタツヤ(贝斯)、Masack(鼓)、平畑彻也(钢琴)六人畅谈一切。超过一万五千字的特别专访。首先想…

vscode+edie插件配置STM32开发环境,彻底摆脱KEIL

安装 首先去vscode官网下载适合自己的安装包,一般来说选择 User Installer x64 即可,具体安装过程请参考其他教程,此处不再赘述: Vscode官网安装完成后打开,在左侧边栏打开插件市场,搜索并安装如下四个插件:C/C++ (C语言代码提示的核心插件) Chinese (中文显示) Emb…

本地部署DeepSeek并用Python调用

本地部署DeepSeek并用Python试调用之,总体来说过程比较顺畅。目录需要下载的软件安装步骤安装Ollama并运行模型DeepSeek安装Hollama试用python调用 需要下载的软件OllamaSetup.exe(Ollama是一个管理和运行大语言模型的开源工具) Hollama_0.25.1-win-x64.exe【可选】(Hollam…

12 网络编程详解

知识预备网络通信 :​ 网络通信是指,将一台设备(Host1)中的数据通过网络传输到另一台设备(Host2)。java.net 包下提供了许多用于完成网络通信的类或接口。 ​ 相关流程图如下 :网络 :​ 两台或两台以上的设备通过一定物理设备(交换机,网关服务器等等)连接起来…

25.2.4小记(FoxandRabbit代码复现)

1.接口(interface)不仅可以用于定义方法的签名,还可以充当类型的一部分。其本身可以作为类来引用 eg.Cell[][] field 数组中的对象是实现了这个接口的类的实例。 是一种特殊的classreturn list.toArray(new Cell[list.size()]);中list.toArray是将原来的数组填充到()中的对…

2015 纯碱

回调后有一波多头行情

2015 锰硅

年后回调后有波多头行情 具体等交易系给出信号

2024 山东一轮省集组合计数选讲学习笔记

https://www.luogu.com/article/hcy6mqry 初等双射 通常的方法是构造一个不会映射到自己的对合,这样就就可以把所有的组合对象分为数量相等的两类。 还有一种方法就是给等式两边找到一个相同的组合意义,以证明他们相等,这个不一定是一个映射,它允许“一对多”“多对一”。 …

TCP和UDP协定的基础知识解析,从网路效能到网路安全看TCP、UDP协议

TCP和UDP协定的基础知识解析,从网路效能到网路安全看TCP、UDP协议TCP和UDP协定是网路通讯中不可或缺的基础。 TCP以其可靠性著称,能够确保资料完整传输,适合文件传输和邮件服务等场景。它透过建立连接和确认机制,提供稳定的通讯体验。相比之下,UDP更注重速度和即时性。它无…