比赛链接

A

题解

知识点:贪心,数学。

注意到三段工作时间一共 \(n-3\) 天,且天数实际上可以随意分配到任意一段,每段至少有一天,现在目的就是最大化段差最小值。

不妨设 \(l_1<l_2<l_3\) ,显然满足等式 \(l_2-l_1 = l_3-l_2 = k\) 时段差相等,即没有长度被浪费。

解得 \(2l_2-l_1 = l_3\) ,于是 \(3l_2 = n-3\) ,即 \(l_2 = \lfloor \frac{n-3}{3} \rfloor\) ,现在考虑余数部分分配。显然,多余的一天或者两天分配到 \(l_3\) 不会影响段差最小值,但分配到 \(l_1,l_2\) 只可能变小,所以 \(l_2\) 只能是 \(\lfloor \frac{n-3}{3} \rfloor\) ,余数全扔进 \(l_3\) 但对答案没影响,因此之后不考虑余数。

为使 \(k\) 最大,显然设 \(l_1 = 1,l_3 = 2l_2-1\) ,因此最终答案是 \(\lfloor \frac{n-3}{3} \rfloor - 1\)

时间复杂度 \(O(1)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; bool solve() {
int n;
cin >> n;
cout << (n - 3) / 3 - 1 << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

B

题解

知识点:贪心。

确定最小值 \(min\) ,把大于等于 \(2min\) 的数拆分了即可,且不会影响最小值。

一个数拆分的最小次数是 \(\lceil \frac{n}{2min-1} \rceil -1\) ,方法是每次把 \(2min-1\) 拆出来,能拆 \(\lceil \frac{n}{2min-1} \rceil -1\) 次,但最后一次拆会导致剩下的小于 \(min\) ,所以最后一次可以替换成对半拆,但不影响总次数。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int a[107];
bool solve() {
int n;
cin >> n;
for (int i = 1;i <= n;i++) cin >> a[i];
int mi = *min_element(a + 1, a + 1 + n);
mi = mi * 2 - 1;
ll sum = 0;
for (int i = 1;i <= n;i++) {
if (a[i] > mi) sum += (a[i] + mi - 1) / mi - 1;
}
cout << sum << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

C

题解

知识点:贪心,枚举。

显然贪心取能取的最小字母作为密码环中上一个字母。

当自己已经有上一个字母时,可以直接取。

当自己还没有上一个字母时,考虑取的限制:

  1. 自己不能取自己
  2. 已经取过的字母不能再取,即这个字母已经有下一个字母,且不是自己
  3. 把这个字母当作自己的上一个以后,会形成一个环且环的长度不是 \(26\) 时,不能取。

满足上述限制的情况下取最小的字母即可。为了方便,可以只记录每个字母的上一个字母和有没有下一个字母,每个字母的下一个字母具体是什么其实不重要。

时间复杂度 \(O(n \cdot 26^2)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; bool vis[26];
int pst[26]; bool check(int a, int b) {
if (vis[b] || a == b) return false;
int k = b, cnt = 0;
while (~pst[k]) {
k = pst[k];
cnt++;
}
return k != a || cnt == 25;
} bool solve() {
memset(vis, 0, sizeof(vis));
memset(pst, -1, sizeof(pst));
int n;
cin >> n;
string s;
cin >> s;
string ans;
for (int i = 0;i < s.size();i++) {
if (~pst[s[i] - 'a']) {
ans += pst[s[i] - 'a'] + 'a';
continue;
}
for (int j = 0;j < 26;j++) {
if (check(s[i] - 'a', j)) {
vis[j] = 1;
pst[s[i] - 'a'] = j;
ans += j + 'a';
break;
}
}
}
cout << ans << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

D

题解

知识点:枚举,数学,STL。

配成 set 的卡牌各个特征和都能被 \(3\) 整除,即 \(c[i][l] + c[j][l] + c[k][l] \equiv 0 \pmod 3\) ,表示能组成 set 的 \(i,j,k\) 三张牌的任意特征 \(l\) 的情况。

注意到卡牌两两不同,因此通过两张卡牌就能唯一确定另一张可以配对成 set 的卡牌的牌型,即 \(c[i][l] \equiv -c[j][l] - c[k][l] \pmod 3\) ,表示通过 \(j,k\) 两张牌能确定 \(i\) 的牌型,这也意味着不同的 set 至少有两张牌不同。

想要组成一个 meta-set ,需要五张牌组成至少两个 set ,但根据上面的结论,两个 set 至多有一个重复的牌,就已经有五张牌了。因此一个 meta-set 有五张牌,需要且只需要组成两个 set ,且其中一张牌会同时存在于两个 set

因此我们先遍历所有两张牌的组合(称为一对牌),得到能够和这一对牌组成 set 的牌型,并在这种牌型下计数,表示这种牌型可以和几对牌组成 set 。假如某种牌型下存在 \(cnt\) 对牌,则可以从中选 \(2\) 对组成 meta-set ,总计有 \(C_{cnt}^2\) 种方案。

最后遍历一遍牌,并通过之前记录的牌型与对数,计算方案总数,根据上面结论,这些方案不可能交叉。

时间复杂度 \(O(n^2k\log n)\)

空间复杂度 \(O(nk)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; bool solve() {
int n, k;
cin >> n >> k;
vector<vector<int>> c(n + 1, vector<int>(k));
for (int i = 1;i <= n;i++)
for (int j = 0;j < k;j++)
cin >> c[i][j];
map<vector<int>, int> mp;
for (int i = 1;i <= n;i++) {
for (int j = i + 1;j <= n;j++) {
vector<int> v(k);
for (int l = 0;l < k;l++)
v[l] = (6 - c[i][l] - c[j][l]) % 3;//找到与两张卡牌配对的第三张卡牌
mp[v]++;
}
}
int ans = 0;
for (int i = 1;i <= n;i++) {
int tmp = mp[c[i]];
ans += (tmp - 1) * tmp / 2;
}
cout << ans << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
//cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

E

题解

知识点:枚举,STL。

因为 \(h_i\) 到 \(p_1,p_2\) 的距离是打乱的,可以通过枚举 \(p_1,p_2\) 之间的可能的间距,检查这个距离 \(dis\) 是否合法,从而推断出可能序列。

先固定一个端点的距离 \(d_1[0]\) ,匹配另一个端点距离 \(d_2[i]\) ,这样就能枚举到所有情况。此时有两种情况,第一种是点在 \(p_1,p_2\) 之间,即 \(dis = d_1[0] + d_2[i]\) ,第二种是点在 \(p_1,p_2\) 之外,即 \(dis = |d_1[0]-d_2[i]|\) ,两种都枚举一下即可。

先假设 \(p_1 = 0,p_2 = dis\) 。

在判断一个 \(dis\) 是否合法时,先把距离 \(x\) 大于 \(dis\) 的处理掉,即找到当前 \(d_1,d_2\) 中最大的且大于 \(dis\) 的,这种情况的点只可能在 \(p_1,p_2\) 之外。假设 \(x\) 在 \(d_1\) 中, \(diff = x-dis\) 一定存在于 \(d_2\) 中,否则就是 \(dis\) 不合法。存在的话就把 \(x,diff\) 从 \(d_1,d_2\)删掉, \(p_1+x\) 就是 \(h_i\) 之一。

之后没有在 \(p_1,p_2\) 之外的点时,剩下的点都在内部,则把当前 \(d_1\) 从小到大排序,\(d_2\) 从大到小排序,其对应位置之和都应该等于 \(dis\) ,否则就不合法。

最后要求输出非负数,所以把整个序列偏移一下即可。

时间复杂度 \(O(n^2\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
#define ll long long using namespace std; int n;
int d1[1007], d2[1007]; struct node {
multiset<int> ms;
void insert(int x) { ms.insert(x); }
int max() { return *prev(ms.end()); }
int size() { return ms.size(); }
void erase(int x) { ms.erase(ms.find(x)); }
bool exist(int x) { return ms.find(x) != ms.end(); }
}; bool check(int dis) {
node ms1, ms2;
for (int i = 1;i <= n;i++) ms1.insert(d1[i]), ms2.insert(d2[i]); int p1 = 0, p2 = dis;
vector<int> ans;
while (ms1.size() && ms2.size() && max(ms1.max(), ms2.max()) >= dis) {//先清理在假定的p1,p2外的点
if (ms1.max() > ms2.max()) {//|p1-h|最长
int x = ms1.max();
int diff = x - dis;
if (!ms2.exist(diff)) return false;
ms1.erase(ms1.max());
ms2.erase(diff);
ans.push_back(p1 + x);
}
else {//|p2-h|最长
int x = ms2.max();
int diff = x - dis;
if (!ms1.exist(diff)) return false;
ms1.erase(diff);
ms2.erase(ms2.max());
ans.push_back(p2 - x);
}
} vector<int> v1, v2;
for (auto i : ms1.ms) v1.push_back(i);
for (auto i : ms2.ms) v2.push_back(i);
reverse(v2.begin(), v2.end());
for (int i = 0;i < v1.size();i++) {//其他点都在内部
if (v1[i] + v2[i] != dis) return false;
} for (auto i : v1) ans.push_back(i);
int diff = max(-*min_element(ans.begin(), ans.end()), 0);//保证最小坐标是非负的
cout << "YES" << '\n';
for (auto i : ans) cout << i + diff << ' ';
cout << '\n';
cout << diff << ' ' << dis + diff << '\n';
return true;
} bool solve() {
cin >> n;
for (int i = 1;i <= n;i++) cin >> d1[i];
for (int i = 1;i <= n;i++) cin >> d2[i];
for (int i = 1;i <= n;i++) {
if (check(abs(d1[1] - d2[i]))) return true;
if (check(d1[1] + d2[i])) return true;
}
return false;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

Codeforces Round #824 (Div. 2) A-E的更多相关文章

  1. Codeforces Round #366 (Div. 2) ABC

    Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...

  2. Codeforces Round #354 (Div. 2) ABCD

    Codeforces Round #354 (Div. 2) Problems     # Name     A Nicholas and Permutation standard input/out ...

  3. Codeforces Round #368 (Div. 2)

    直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...

  4. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  5. Codeforces Round #279 (Div. 2) ABCDE

    Codeforces Round #279 (Div. 2) 做得我都变绿了! Problems     # Name     A Team Olympiad standard input/outpu ...

  6. Codeforces Round #262 (Div. 2) 1003

    Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...

  7. Codeforces Round #262 (Div. 2) 1004

    Codeforces Round #262 (Div. 2) 1004 D. Little Victor and Set time limit per test 1 second memory lim ...

  8. Codeforces Round #371 (Div. 1)

    A: 题目大意: 在一个multiset中要求支持3种操作: 1.增加一个数 2.删去一个数 3.给出一个01序列,问multiset中有多少这样的数,把它的十进制表示中的奇数改成1,偶数改成0后和给 ...

  9. Codeforces Round #268 (Div. 2) ABCD

    CF469 Codeforces Round #268 (Div. 2) http://codeforces.com/contest/469 开学了,时间少,水题就不写题解了,不水的题也不写这么详细了 ...

  10. 贪心+模拟 Codeforces Round #288 (Div. 2) C. Anya and Ghosts

    题目传送门 /* 贪心 + 模拟:首先,如果蜡烛的燃烧时间小于最少需要点燃的蜡烛数一定是-1(蜡烛是1秒点一支), num[g[i]]记录每个鬼访问时已点燃的蜡烛数,若不够,tmp为还需要的蜡烛数, ...

随机推荐

  1. xshell配置隧道转移规则

    钢铁知识库,一个学习python爬虫.数据分析的知识库.人生苦短,快用python. xshell是什么 通俗点说就是一款强大ssh远程软件,可以方便运维人员对服务器进行管理操作,功能很多朋友们自行探 ...

  2. Blazor模式讲解

    Blazor的三种模式 Blazor Server: Blazor Server在 ASP.NET Core 应用中支持在服务器上托管 Razor 组件. 可通过 SignalR 连接处理 UI 更新 ...

  3. [转帖]tcplife的使用

    https://www.rutron.net/posts/2203/bcc-tcplife-usage/ 这篇文档主要演示了 tcplife(Linux eBPF/bcc) 工具的使用. 示例 tcp ...

  4. 人大金仓学习之一_kwr的简单学习

    人大金仓学习之一_kwr的简单学习 摘要 周末在家想着学习一下数据库相关的内容. 网上找了不少资料, 想着直接在本地机器上面进行一下安装与验证 理论上linux上面应该更加简单. windows 上面 ...

  5. ChatGPT 提高工作效率-一例SQL编写的过程

    ChatGPT 提高工作效率-一例SQL编写的过程 前言 遇到一个问题, 怀疑是有一些补丁没有被依赖. 导致第一次更新时没有更新这些没依赖的补丁. 后面更新时又更新了这些游离态的补丁. 导致出现 ol ...

  6. [转帖]龙芯总强调同频性能,是因奔腾4要到25+GHz才比得上酷睿11代单核

      https://baijiahao.baidu.com/s?id=1734320620568707041 闲话不说,先上图,是SPEC CPU 2006 int(单任务)测试的成绩: 上图中的成绩 ...

  7. [转帖]Windows系统内置测试工具(winsat)

    WinSAT 是 Windows 系统评估工具(Windows System Assessment Tool)的缩写,是从 Windows Vista 开始便内置于系统之中的命令行工具,可对 Wind ...

  8. [转帖]Java 类加载器

      类的生命周期和加载过程 在Java中数据类型分为基本数据类型和引用数据类型.基本数据类型由虚拟机预先定义,引用数据类型则需要进行类的加载.引用类型,Java 将其细分为四种:类.接口.数组类和泛型 ...

  9. 文心一言 VS 讯飞星火 VS chatgpt (186)-- 算法导论14.1 3题

    三.用go语言,写出OS-SELECT的非递归版本. 文心一言: 下面是使用Go语言编写的OS-SELECT的非递归版本: func OS_SELECT(T *Node, k int) *Node { ...

  10. postman中js脚本简单用法

    1.获取接口相应结果 var jsonData = pm.response.json() 2.设置环境变量 pm.environment.set("variable_key", & ...