没有手速,再加上被 E 卡了,废掉了。

A.GamingForces

题目描述:

Monocarp 正在玩电脑游戏。他打算杀死 \(n\) 个怪兽,第 \(i\) 个的血量为 \(h_i\)。

Monocarp 的角色有两个魔法咒语如下,都可以以任意顺序用任意次(可以不用),每次使用相当于一次操作。

  1. 选择两个怪兽并扣一滴血。

  2. 选择一个怪兽并且直接杀死。

当一个怪兽血量为 \(0\) 时,他死了

求杀死所有怪兽的最少操作次数。

题目分析:

只有两个怪兽同为 \(1\) 点血,这个时候我们通过 \(1\) 操作直接把它们弄死才会比直接通过操作 \(2\) 直接弄死更优。

所以判一下这个就好了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 10005;
int a[N];
int main(){
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int cnt = 0;
for(int i=1; i<=n; i++){
if(a[i] == 1) ++cnt;
}
printf("%d\n",n - cnt / 2);
}
return 0;
}

B.Stand-up Comedian

题目描述:

Eve 是个单口相声新手。她的第一场表演聚集了总计 \(2\) 个观众:Alice 和 Bob。

Eve 准备了 \(a_1+a_2+a_3+a_4\) 个相声表演节目。\(a_i\) 表示第 \(i\) 类相声的数目,每类的的特征如下:

  1. Alice 和 Bob 都喜欢这类相声。

  2. Alice 喜欢,Bob 不喜欢。

  3. Bob 喜欢,Alice 不喜欢。

  4. Alice 和 Bob 都不喜欢这类相声。

一开始,两位观众的心情都为 \(0\)

当一位观众听到他喜欢的相声表演时心情会加 \(1\),当听到的是自己不喜欢的相声时,心情减 1

当某位观众心情严格小于 \(0\) 时,这位观众会离场。只要有一位这样的观众离场,Eve 会特别伤心并且结束整个表演。若演完了所有节目,也会结束表演。

求某种安排表演顺序的方式,使得 Eve 在结束表演前能表演的节目最多。输出最多能表演的节目数。

译者注:若演完某个节目有观众退场,这个节目也算在总数之中

\(0 \le a_1,a_2,a_3,a_4 \le 10^8\)。

题目分析:

好像是个大细节题,但是我一遍过就很爽[狂笑]

考虑最优的一个操作顺序肯定是:\(1 \to 2,3 \to 4\)。

关键是中间 \(2,3\) 造成的贡献比较难算,可以显然发现我们先操作一次 \(2\) 后操作一次 \(3\) 它们的代价就抵消了,而且会多出两次节目,但是要注意如果 \(1\) 操作数量为 \(0\) 就不能相互抵消了。

所以就按照:操作 \(1\)、\(2,3\) 抵消、操作 \(2,3\)、操作 \(4\),这样的顺序模拟一下即可。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int cnt[10];
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%lld",&T);
while(T--){
for(int i=1; i<=4; i++) scanf("%lld",&cnt[i]);
int ans = 0;
int a = cnt[1],b = cnt[1];ans += cnt[1];
if(a == 0){
if(cnt[2] + cnt[3] + cnt[4] > 0) printf("1\n");
else printf("0\n");
continue;
}
int tmp = min(cnt[2],cnt[3]);ans += 2 * tmp;
cnt[2] -= tmp,cnt[3] -= tmp;
if(cnt[2] > 0){
tmp = min(cnt[2],b+1);ans += tmp;
a += tmp,b -= tmp;
}
if(cnt[3] > 0){
tmp = min(cnt[3],a+1);ans += tmp;
a -= tmp,b += tmp;
}
if(a >= 0 && b >= 0){
ans += min(min(a+1,b+1),cnt[4]);
}
printf("%lld\n",ans);
}
return 0;
}

C.Min Max Sort

题目描述:

对于一个排列,定义一次操作为:在排列中任选两个数字,将它们中的最大值插入至队尾,最小值插入至队首。

现在给定多个排列,问每个排列最少各需多少次操作才能变得严格递增。

\(1 \le n\le 2\times 10^5\)

题目分析:

如果我们要进行操作,那么最后 \(1\) 操作必然是 \(1,n\),然后倒推一下就会发现倒数第 \(2\) 次操作必然是 \(2,n-1\),然后就可以发现倒数第 \(i\) 次操作必然是 \(i,n-i+1\)。

所以假设我们通过 \(k\) 次操作可以使排列严格递增,也就是说值在 \([k+1,n-k]\) 是不用我们管的了,已经符合条件了,将两头的 \(k\) 个进行排完序就结束了。

这个“不用管”用形式化的语言说其实就是,设 \(pos_i\) 表示数 \(i\) 出现的位置,则 \(pos_{k+1} < pos_{k+2} < \cdots < pos_{n-k}\)。

所以可以直接一个个枚举 \(k\) 判断是否合法即可,也就是将 \(k\) 从 \(\lfloor \frac{n}{2} \rfloor\) 开始依次减 \(1\),然后判断条件是否满足。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int a[N],p[N];
int main(){
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]),p[a[i]] = i;
int k = n / 2;
while(k && p[k] < p[k+1] && p[n-k] < p[n-k+1]) --k;
printf("%d\n",k);
}
return 0;
}

D.Fixed Prefix Permutations

题目描述:

对于一个排列 \(p\),定义其美丽度 \(k\) 为

  • \(p_1=1,p_2=2,\cdots,p_k=k,p_{k+1} \neq k+1\)

若 \(p,q\) 均为长度为 \(n\) 的排列,定义排列的运算 \(p \cdot q\) 为:

  • \(p \cdot q = r\),\(p,q,r\) 均为长度为 \(n\) 的排列
  • \(r_j = q_{p_j}\)

现在给出 \(n\) 个长度为 \(m\) 的排列,对于每一个 \(a_i\),求 \(a_i \cdot a_j(1 \le j \le n)\) 美丽值最大为多少,允许有 \(i=j\)。

多测,\(T \le 10^4\),\(\sum n \le 5 \times 10^4\),\(m \le 10\)

题目分析:

考虑如果就是给定了两个排列 \(p,q\) 怎么算它的美丽值。

要让 \(i\) 经过两个排列的置换后依旧是在 \(i\) 的位置,其实就是说设 \(pos_i\) 表示 \(i\) 在 \(q\) 中的位置,则 \(p_i = pos_i\),可以将置换理解为走路这种东西然后就很好理解了。

所以其实就是求出 \(pos\) 之后两者的 \(lcp\)。

那么这个题就很好解决了,可以直接对于每一个排列都求出 \(pos\),然后插入到 trie 树里,计算答案就是枚举每一个排列然后让它在字典树上走即可。

(我竟然一开始用了 bitset 维护这个过程,差点就过了)

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e4+5;
int n,m,a[N][11],tot = 1,pos[N][11],ch[100 * N][11];
void insert(int x){
int now = 1;
for(int i=1; i<=m; i++){
int to = pos[x][i];
if(!ch[now][to]) ch[now][to] = ++tot;
now = ch[now][to];
}
}
int find(int x){
int now = 1;
int ans = 0;
for(int i=1; i<=m; i++){
if(ch[now][a[x][i]]){
++ans,now = ch[now][a[x][i]];
}
else break;
}
return ans;
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
scanf("%d",&a[i][j]);
pos[i][a[i][j]] = j;
}
insert(i);
}
for(int i=1; i<=n; i++) printf("%d ",find(i));
printf("\n");
for(int i=1; i<=tot; i++){
for(int j=1; j<=10; j++){
ch[i][j] = 0;
}
}
tot = 1;
}
return 0;
}

E.Divisors and Table

题目描述:

给定一张 \(n \times n\) 的表格和一个正整数 \(m = m_1 \times m_2\),表格第 \(i\) 行第 \(j\) 列的数 \(a_{i, j} = i \times j\)。

现在需要你求出 \(m\) 的每个因子 \(d\) 是否在表格中出现,若出现,则求出其出现在表格中的最小行号。

\(1 \le n, m_1, m_2 \le 10^9\)

题目分析:

(一种乱搞做法)

\(10^{18}\) 以内的数,因子个数最多有大约 \(10^5\) 个,所以显然可以将 \(m\) 的的所有因子都拿出来然后挨个判断。

要求所有的因子其实就是要对 \(m\) 质因数分解,可以直接用科技对 \(m\) 分解,也可以分别为 \(m_1,m_2\) 分解后合起来,这样我们就得到了 \(m\) 的所有因子。

我们要做的其实就是分解 \(d = a \times b\),且 \(a,b \le n\),要求 \(a\) 尽可能小。

因为 \(d\) 为 \(m\) 的因子,所以 \(a,b\) 也必然是 \(m\) 的因子,所以可以将因子排序之后二分。

具体来说就是二分最小的 \(a\) 使得 \(\lceil \frac{d}{a} \rceil \le n\),这样只需要向后枚举一些 \(a\) 使得 \(a \mid d\) 此时 \(a\) 就是最优的 \(a\) 了。

代码:

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector> using namespace std; #define int long long int t, n, m1, m2;
vector<int> a, b, c; signed main()
{
scanf("%lld", &t);
while (t -- )
{
int cnt = 0, ans = 0;
a.clear();
b.clear();
c.clear(); scanf("%lld%lld%lld", &n, &m1, &m2);
for (int i = 1; i <= m1 / i; i ++ )
{
if(m1 % i == 0)
{
a.push_back(i);
if(m1 / i != i) a.push_back(m1 / i);
}
}
for (int i = 1; i <= m2 / i; i ++ )
{
if(m2 % i == 0)
{
b.push_back(i);
if(m2 / i != i) b.push_back(m2 / i);
}
}
sort(a.begin(), a.end());
sort(b.begin(), b.end()); for (int i = 0; i < a.size(); i ++ )
for (int j = 0; j < b.size(); j ++ )
c.push_back(a[i] * b[j]); sort(c.begin(), c.end());
c.erase(unique(c.begin(), c.end()), c.end()); for (int i = 0; i < c.size(); i ++ )
{
int l = 0, r = i;
while (l <= r)
{
int mid = l + r >> 1;
if ((c[i] + c[mid] - 1) / c[mid] <= n) r = mid - 1;
else l = mid + 1;
}
for (int j = l; j < c.size(); j ++ )
{
if(c[j] > n) break;
if(c[i] % c[j] == 0)
{
ans ^= c[j];
cnt ++;
break;
}
}
}
printf("%lld %lld\n", cnt, ans);
}
}

F1.Graph Coloring

题目描述:

简单版和困难版之间的唯一区别是 \(n\) 的数据范围不同。

给出一个 \(n\) 个顶点的无向完全图。完全图是指图上任意两个顶点皆有一条边相连。你需要给图上的每条边染上红色或蓝色。

一个顶点的集合 \(S\) 被称作是红色连接的,如果对于 \(S\) 中每对顶点 \((v_1,v_2)\),都存在只通过红边和 \(S\) 中顶点的路径。相仿地,一个顶点的集合 \(S\) 被称作是蓝色连接的,如果对于 \(S\) 中每对顶点 \((v_1,v_2)\),都存在只通过蓝边和 \(S\) 中顶点的路径。

你需要以如下方式对图进行染色:

  • 至少有一条红边。
  • 至少有一条蓝边。
  • 对于每个大小不小于 \(2\) 的顶点集 \(S\)(也即 \(|S|\geqslant 2\)),\(S\) 或者是红色连接的,或者是蓝色连接的,但不能同时是红色和蓝色连接的。

计算染色方法数对 \(998244353\) 取模后的结果。

\(1\le n \le 5\times 10^3\)

题目分析:

(不写 F2 了,是一个多项式科技)

题目条件就是要求对于任意一个导出子图,要么通过红色边可以联通,要么通过蓝色边可以联通,但是不能通过两种边都可以联通。

注意到一点就是:这是一个完全图,所以蓝色边和红色边互为补图,也就是如果蓝色边不连通则红色边必然联通,反之亦然。

所以我们可以直接 \(dp_n\) 表示节点个数为 \(n\) 的图,不能通过蓝色边联通的合法的方案数。

转移就是考虑枚举点 \(n\) 所在的蓝色连通块大小 \(x\):

\[dp_n = \sum_{x=1}^{n-1} \binom{n-1}{x-1} dp_x \times (2 - [x = n-1])dp_{n-x}
\]

对于 \(n\) 所在的连通块这 \(x\) 个点必然满足蓝色联通也就是红色不连通,方案数等同于 \(dp_x\)。

对于其余的 \(n-x\) 个点,它们之间蓝色联通或者红色联通都可以,所以就是系数有 \(2\) 的贡献,但当 \(n-x = 1\) 时,显然只有一种方案。

因为题目要求必须同时出现红边和蓝边,所以将答案减 \(2\) 即可。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e3+5;
const int MOD = 998244353;
int fac[N],inv[N],f[N];
int binom(int n,int m){
if(n < m || n < 0 || m < 0) return 0;
return fac[n] * inv[m] % MOD * inv[n-m] % MOD;
}
int power(int a,int b){
int res = 1;
while(b){
if(b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
signed main(){
int n;scanf("%lld",&n);
fac[0] = 1;
for(int i=1; i<=n; i++) fac[i] = fac[i-1] * i % MOD;
inv[n] = power(fac[n],MOD-2);
for(int i=n-1; i>=0; i--) inv[i] = inv[i+1] * (i+1) % MOD;
f[1] = 1;
for(int i=2; i<=n; i++){
for(int j=1; j<=i-1; j++){
f[i] = (f[i] + f[j] * f[i-j] %MOD* binom(i-1,j-1) * (2 - (j == i-1))%MOD)%MOD;
}
}
printf("%lld\n",(2 * f[n] %MOD - 2 + MOD)%MOD);
return 0;
}

【题解】Educational Codeforces Round 142(CF1792)的更多相关文章

  1. Educational Codeforces Round 142 (Rated for Div. 2) A-D

    比赛链接 A 题解 知识点:贪心. 代码 #include <bits/stdc++.h> using namespace std; using ll = long long; bool ...

  2. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  3. Educational Codeforces Round 48 (Rated for Div. 2) CD题解

    Educational Codeforces Round 48 (Rated for Div. 2) C. Vasya And The Mushrooms 题目链接:https://codeforce ...

  4. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

  5. Educational Codeforces Round 59 (Rated for Div. 2) DE题解

    Educational Codeforces Round 59 (Rated for Div. 2) D. Compression 题目链接:https://codeforces.com/contes ...

  6. Educational Codeforces Round 58 (Rated for Div. 2) 题解

    Educational Codeforces Round 58 (Rated for Div. 2)  题目总链接:https://codeforces.com/contest/1101 A. Min ...

  7. Educational Codeforces Round 65 (Rated for Div. 2)题解

    Educational Codeforces Round 65 (Rated for Div. 2)题解 题目链接 A. Telephone Number 水题,代码如下: Code #include ...

  8. Educational Codeforces Round 64 (Rated for Div. 2)题解

    Educational Codeforces Round 64 (Rated for Div. 2)题解 题目链接 A. Inscribed Figures 水题,但是坑了很多人.需要注意以下就是正方 ...

  9. Educational Codeforces Round 64 部分题解

    Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...

  10. Educational Codeforces Round 64部分题解

    Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...

随机推荐

  1. nginx 反向代理proxy_pass 后加斜杠和不加斜杆的区别

    今日准备使用nginx 将上次使用docker 部署的一个vue项目进行地址代理,让他看起来高达尚一点,原本docker打包的镜像只是向外暴露了一个8191的端口,访问的时候就只能是 http://w ...

  2. nas盒子内网穿透

    2023年5月27日星期六 -------------------------------------------------------------------------------------- ...

  3. Mdnice 简洁主题

    Md2All 是个人非常喜欢的一个 Markdown 排版工具,也是一直以来本公众号推文排版编辑的主要阵地.但发现 Md2All 有时候会非常卡(不太清楚是不是 Md2All 用了国外的服务器),而且 ...

  4. Google Chrome 超详细使用教程

    由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中的链接. 调查统计机构 NetMarketShare 发布最新的 7 月份报告,在全球浏览器市场,谷歌 ...

  5. Asp-Net-Core开发笔记:API版本管理

    前言 对于Web API应用程序而言,随着时间的推移以及需求的增加或改变,API必然会遇到升级的需求.事实上,Web API应用程序应该从创建时就考虑到API版本的问题.业务的调整.功能的增加.接口的 ...

  6. CANoe _ Panel面板的创建过程

    在Canoe中创建Panel面板,用于显示和操作CAN网络的数据和信号,遵循以下步骤: 1.打开Canoe 启动Canoe软件. 2.打开项目 在Canoe的菜单栏中,选择"File&quo ...

  7. Spring Boot 通用对象列表比较和去重

    1.前言   在Excel批量导入数据时,常常需要与数据库中已存在数据的比较,并且需要考虑导入数据重复的可能性.   导入的行数据,一般有一个实体类(对象)与之对应,往往这个实体类在数据库中的字段要比 ...

  8. CKS 考试题整理 (02)-Apparmor

    Context Apparmor 已在 cluster 的工作节点 node02 上被启用.一个 Apparmor 配置文件已存在,但尚未被实施. Task 在 cluster 的工作节点 node0 ...

  9. 基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发

    基于Avalonia 11.0.0+ReactiveUI 的跨平台项目开发2-功能开发 项目简介:目标是开发一个跨平台的AI聊天和其他功能的客户端平台.目的来学习和了解Avalonia.将这个项目部署 ...

  10. 【技术积累】Vue.js中的组件库【一】

    Vue组件库是什么 Vue中的组件库是一组预先构建好的可重用组件,用于加速开发过程并提高代码的可维护性.组件库通常包含一系列常用的UI组件,如按钮.输入框.下拉菜单等,以及一些功能性组件,如模态框.轮 ...