SMU Summer 2024 Contest Round 8

Product

思路

注意到 \(\prod\limits_{i=1}^NL_i\le10^5\),也就是说 N 不会超过 16,因为 \(2^{17}>10^5\),所以我们可以直接暴搜。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); i64 n, x;
cin >> n >> x; vector L(n, vector<i64>());
for (int i = 0; i < n; i ++) {
int k;
cin >> k;
vector<i64> a(k);
for (auto &j : a)
cin >> j;
L[i] = a;
} i64 ans = 0;
auto dfs = [&](auto & self, int num, __int128 res)->void{ if (res > x) return; if (num == n) {
if (res == x)
ans ++;
return ;
} for (int i = 0; i < L[num].size(); i ++) {
self(self, num + 1, res * L[num][i]);
} }; dfs(dfs, 0, 1); cout << ans << '\n'; return 0;
}

Dice Sum

思路

考虑 dp。

设 \(dp_{i,j}\) 为前 i 个数中总和为 j 的方案数 则有转移方程:

\[dp_{i,j}=\sum\limits_{k=1}^{min(j,m)}dp_{i-1,j-k}
\]

上面是取模模板太长不放了。

代码

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n, m, k;
cin >> n >> m >> k; vector<vector<Z>> dp(n + 1, vector<Z>(k + 1)); for (int i = 1; i <= m; i ++)
dp[1][i] = 1; for (int i = 2; i <= n; i ++) {
for (int j = 1; j <= k; j ++)
for (int p = 1; p <= min(j, m); p ++) {
dp[i][j] += dp[i - 1][j - p];
}
} Z ans = 0;
for (int i = 0; i <= k; i ++)
ans += dp[n][i]; cout << ans << '\n'; return 0;
}

Ubiquity

思路

每一个位置有 10 种选择,总方案数为 \(10^N\) 种,选定一个为 0/9 的方案数有 \(9^N\) 种,直接相减会多减去 0 和 9 的方案数,需要加上 \(8^N\) 。

即:

\[10^N-2\times9^N+8^N
\]

上快速幂搞一下即可。

代码

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n;
cin >> n; cout << Z(power(Z(10), n) - 2 * power(Z(9), n) + power(Z(8), n)) << '\n'; return 0;
}

FG operation

思路

考虑 dp。

因为每次是删掉前两个数,所以考虑从左往右转移。

设 \(dp_{i,j}\) 表示为删掉第 i 个数后 \((x+y)\%10\) 为 j 的方案数。

转移方程为 :

\[dp_{i,(j+a_i)\bmod 10}=dp_{i,(j+a_i)\bmod 10}+dp_{i-1,j}
\]
\[dp_{i,(j\times a_i)\bmod 10}=dp_{i,(j\times a_i)\bmod 10}+dp_{i-1,j}
\]

代码

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n;
cin >> n; vector<i64> a(n + 1);
for (int i = 1; i <= n; i ++)
cin >> a[i]; vector<vector<Z>> dp(n + 1, vector<Z>(10)); dp[1][a[1]] = 1;
for (int i = 2; i <= n; i ++) {
for (int j = 0; j <= 9; j ++) {
dp[i][j * a[i] % 10] += dp[i - 1][j];
dp[i][(j + a[i]) % 10] += dp[i - 1][j];
}
} for (int i = 0; i <= 9; i ++) {
cout << dp[n][i] << '\n';
} return 0;
}

Left Right Operation

思路

前缀和后缀和枚举 L 和 R 两数更新前后缀更小的和,然后枚举 i 找到最小的答案即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); i64 n, l, r;
cin >> n >> l >> r; vector<i64> a(n + 1), pre(n + 1), suf(n + 2);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
pre[i] = pre[i - 1] + a[i];
} for (int i = 0; i <= n; i ++) {
pre[i] = min(pre[i], i * l);
} for (int i = n; i >= 1; i --) {
suf[i] = min(suf[i + 1] + a[i], (n - i + 1) * r);
} i64 ans = 1e15;
for (int i = 0; i <= n; i ++) {
ans = min(ans, pre[i] + suf[i + 1]);
} cout << ans << '\n'; return 0;
}

Add and Mex

思路

根据 Mex 的性质,只有在 \([0,N]\) 的范围内才会对答案有贡献,且最大答案为 N + 1,又因为每次 +i,所以一个数会在第 \(\frac Ni\) 超过 N ,不再对答案产生贡献,因此我们可以求出一个数会在哪个区间内对答案产生贡献,即 \(0\le a_i+k\times i\le N\),得出 \(k\in [\lceil\frac{-a_i}{i}\rceil,\lfloor\frac{N-a_i}{i}\rfloor]\),这样枚举区间是一个调和级数级别的,即最终复杂度为 \(O(nln\ n)\) ,然后对于每一次询问暴力枚举区间内的 Mex 值即可。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n, m;
cin >> n >> m; vector idx(m + 1, set<int>()); for (int i = 1; i <= n; i ++) {
int a;
cin >> a;
int l = max((-a + i - 1) / i, 0), r = max((n - a) / i, 0);
a += l * i;
for (int j = l; j <= min(r, m); j ++, a += i) {
idx[j].insert(a);
}
} for (int i = 1; i <= m; i ++) {
int ans = 0;
while (idx[i].count(ans))
ans ++;
cout << ans << '\n';
} return 0;
}

Diameter set

思路

根据树的直径的性质:树的每一条直径一定经过一个公共点或一条公共边,经过的是点还是边取决于直径的长度为奇数还是偶数。

要找到相隔为 D 也就是树的直径的点的集合,就是要以树的中心为根,找到其子树内相差为 \(\frac D2\) 的点的集合。

树的直径为偶数的时候,这时候说明肯定存在一个中心点,找到离树的中心 \(\frac D2\) 的位置也就是找它子树中以离它儿子结点 \(\frac D2 -1\) 的位置,假设中心点为 mid,其儿子结点子树中共存在 x 个满足要求的集合,cnt 表示一个集合中的满足要求的点数,其中每个集合中只能选择一个点,因为同在一个子树里的两点其连成的路径不会经过树的中心,也就不可能为 D,其次集合中的点也可以不选作为一种方案,所以一个集合产生的贡献就是 cnt+1,所以总方案为 \(\prod\limits_{v\in son_{mid}}(cnt_v+1)\),根据题目要求至少要有两个点,所以我们要减去所有集合只选了一个点的方案数和所有点都没选的方案数,即最终答案就是 \(\prod\limits_{v\in son_{mid}}(cnt_v+1)-\sum\limits_{v\in son_{mid}}cnt_v-1\)。

树的直径为奇数的时候,这时候只存在一条中心边,所以答案只能由这条中心边的两点的子树来产生贡献,即两边的集合点数乘起来 \(cnt_1\times cnt_2\) ,这个时候不能加 1 了,因为只有两个集合,必须要选两个点也就是两个集合一边选一个。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

struct Tree {
int n, d = 0; //顶点,直径,树中心
//自顶向下u到其叶子结点最远距离d1,次长距离d2(与最长路径无公共边)
//p1,p2表示结点u向下更新时是由哪个结点更新来的
//up表示结点u向上到祖宗结点的最远距离
vector<int> d1, d2, p1, p2, up;
vector<vector<int>> g;
Tree(int n): n(n), d1(n + 1), d2(n + 1), g(n + 1), p1(n + 1), p2(n + 1), up(n + 1) {} void add(int u, int v) {
g[u].emplace_back(v);
g[v].emplace_back(u);
}
//求直径//自顶向下求u到叶子结点的最远距离
void dfs(int u, int fa) {
d1[u] = d2[u] = 0;
for (auto v : g[u]) {
if (v == fa)continue;
dfs(v, u);
auto t = d1[v] + 1;
if (t > d1[u]) {
d2[u] = d1[u], p2[u] = p1[u];
d1[u] = t, p1[u] = v;
} else if (t > d2[u]) {
d2[u] = t, p2[u] = v;
}
}
d = max(d, d1[u] + d2[u]);
}
//自底向上求u到其它结点的最长路径
void dfsup(int u, int fa) {
for (auto v : g[u]) {
if (v == fa) continue;
//如果父结点u向下的最长路径经过v
if (p1[u] == v) {
//结点v向上走到最长路径为
//父结点u继续向上的的最长路径和u向下走的次长路径的最大值+边权
up[v] = max(up[u], d2[u]) + 1;
} else {
//如果父结点u向下的最长路径不经过v
up[v] = max(up[u], d1[u]) + 1;
}
dfsup(v, u);
}
} //求树的直径
int FindDiameter() {
dfs(1, 0);
return d;
} //求树的中心
vector<int> FindCenter() {
dfsup(1, 0);
i64 res = INT_MAX;
vector<int> mid;
for (int i = 1; i <= n; i ++) {
auto t = max(d1[i], up[i]);
if (t < res) {
res = t;
vector<int>().swap(mid);
mid.emplace_back(i);
} else if (t == res) {
mid.emplace_back(i);
}
}
return mid;
} }; int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n;
cin >> n; Tree tr1(n);
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
tr1.add(u, v);
} const i64 mod = 998244353;
auto D = tr1.FindDiameter();
auto mid = tr1.FindCenter(); auto calc = [&](auto & self, int u, int fa, int dis, int x)->int{
int res = 0;
if (dis == x) res ++;
for (auto v : tr1.g[u]) {
if (v == fa)continue;
res += self(self, v, u, dis + 1, x);
}
return res;
}; if (D % 2 == 0) {
i64 ans = 1, no = 0, d = D / 2 - 1;
for (auto v : tr1.g[mid[0]]) {
int cnt = 0;
cnt = calc(calc, v, mid[0], 0, d);
ans = ans * (cnt + 1) % mod;
no += cnt;
}
cout << (ans - no - 1 + mod) % mod << '\n';
} else {
i64 d = D / 2;
i64 cnt1 = calc(calc, mid[0], mid[1], 0, d);
i64 cnt2 = calc(calc, mid[1], mid[0], 0, d);
cout << cnt1 * cnt2 % mod << '\n';
} return 0;
}

SMU Summer 2024 Contest Round 8的更多相关文章

  1. 2015 Astar Contest - Round 3 题解

    1001 数长方形 题目大意 平面内有N条平行于坐标轴的线段,且不会在端点处相交 问共形成多少个矩形 算法思路 枚举4条线段的全部组合.分别作为矩形四条边.推断是否合法 时间复杂度: O(N4) 代码 ...

  2. Contest Round #451 (Div. 2)F/Problemset 898F Restoring the Expression

    题意: 有一个a+b=c的等式,去掉两个符号,把三个数连在一起得到一个数 给出这个数,要求还原等式,length <= 1e6 三个数不能含有前导0,保证有解 解法: 铁头过题法,分类然后各种判 ...

  3. Codeforces Round #284 (Div. 2)A B C 模拟 数学

    A. Watching a movie time limit per test 1 second memory limit per test 256 megabytes input standard ...

  4. Sending messages to non-windowed applications -- AllocateHWnd, DeallocateHWnd

    http://delphi.about.com/od/windowsshellapi/l/aa093003a.htm Page 1: How Delphi dispatches messages in ...

  5. Codeforces 240 F. TorCoder

    F. TorCoder time limit per test 3 seconds memory limit per test 256 megabytes input input.txt output ...

  6. cf499B-Lecture 【map】

    http://codeforces.com/problemset/problem/499/B B. Lecture     You have a new professor of graph theo ...

  7. Codeforces 240F. TorCoder 线段树

    线段树统计和维护某一区间内的字母个数.. . . F. TorCoder time limit per test 3 seconds memory limit per test 256 megabyt ...

  8. 物联网学生科协第三届H-star现场编程比赛

    问题 A: 剪纸片 时间限制: 1 Sec 内存限制: 128 MB 题目描写叙述 这是一道简单的题目,假如你身边有一张纸.一把剪刀.在H-star的比赛现场,你会这么做: 1. 将这张纸剪成两片(平 ...

  9. [cf contest 893(edu round 33)] F - Subtree Minimum Query

    [cf contest 893(edu round 33)] F - Subtree Minimum Query time limit per test 6 seconds memory limit ...

  10. 水题 Codeforces Round #307 (Div. 2) A. GukiZ and Contest

    题目传送门 /* 水题:开个结构体,rk记录排名,相同的值有相同的排名 */ #include <cstdio> #include <cstring> #include < ...

随机推荐

  1. C#如何创建一个可快速重复使用的项目模板

    写在前面 其实很多公司或者资深的开发都有自己快速创建项目的脚手架的,有的是魔改代码生成器实现,有的直接基于T4,RazorEngine等模板引擎打造:但无论如何,其最终目的其实就是搭建一个自定义项目模 ...

  2. 高通平台UEFI有关介绍

    高通平台UEFI有关介绍 背景 我需要在高通平台上学习点亮LCD,目前通过同事在别的平台的配置代码,我已经将kernel部分的屏幕点亮了:剩余的工作量就在BP侧,也就是系统刚开机的那一段时间.在开发过 ...

  3. NB-IoT,LoRA,WIFI,蓝牙,Zigbee,MQTT,CoAP之间的关系

    --- title: file_name date: 2020-06-22 07:26:20 categories: tags: - iot - wifi - Bluetooth - MQTT - c ...

  4. 【冷启动#1】实用的MySQL基础

    简单安装一下MySQL Windows下(5.7.x) 本体安装 1.首先先下载安装包,名字如下: mysql-5.7.19-winx64.zip 2.配置环境变量,将解压之后的bin目录添加一下 3 ...

  5. 1.Javascript 快速入门(主要)

    运算 &&运算是与运算,只有所有都为true,&&运算结果才是true: true && true; // 这个&&语句计算结果为tru ...

  6. Spring DI(依赖注入)自动装配 @Autowired、@Resource注解

    @Autowired:一部分功能是查找实例,从Spring容器中根据类型(Java类)获取对应的实例:另一部分功能就是赋值,将找到的实例,装配给另一个实例的属性值.(注:一个Java类型在同一个Spr ...

  7. [无线隔离]同一WIFI下两主机无法互联

    问题描述 在公司WIFI下想进行两台主机之间的数据传输,却发现虽在同一网段且防火墙关闭也无法ping通. 在一台主机下查看ARP表,发现没有对方的IP与MAC记录. 使用Wireshark抓包,发现虽 ...

  8. XAMPP的mysql启动失败:Plugin ‘FEEDBACK‘ is disabled

    安装完XAMPP后启动mysql,发现启动失败也没有任何提示,通过查看mysql_error日志,描述: 2021-08-11 18:56:53 0 [Note] InnoDB: Mutexes an ...

  9. 可视化—AntV G6实现节点连线及展开收缩分组

    AntV 是蚂蚁金服全新一代数据可视化解决方案,主要包含数据驱动的高交互可视化图形语法G2,专注解决流程与关系分析的图表库 G6.适于对性能.体积.扩展性要求严苛的场景. demo使用数字模拟真实的节 ...

  10. C# 对象复制三种方法效率对比——反射、序列化、表达式树

    1.需求 在代码中经常会遇到需要把对象复制一遍,或者把属性名相同的值复制一遍. 比如: public class Student { public int Id { get; set; } publi ...