评价:educational

A.Make it Beautiful

题目描述:

如果一个数组中存在一个数恰好等于该数前面所有数之和,那么这个数组就是丑的。如果一个数组不是丑的,就是美的。

比如说:

  • 数组 $ [6, 3, 9, 6] $ 是丑的,因为 \(9 = 6 + 3\) ;
  • 数组 $ [5, 5, 7] $ 是丑的,因为第二个 \(5 = 5\) 。
  • 数组 $ [8, 4, 10, 14] $ 是美的,因为 $ 8 \ne 0 $ , $ 4 \ne 8 $ , $ 10 \ne 8 + 4 $ , $ 14 \ne 8 + 4 + 10 $ ,没有任何一个数等于它前面的数之和。

给定数组 \(a\) 满足 $ 1 \le a_1 \le a_2 \le \dots \le a_n \le 100 $ 。 你可以任意调整元素的顺序,也可以不调整,使它变成一个美的数组。

题目分析:

我们可以考虑从大到小排序,这样除了最大值可能出问题,其它的都没问题。

而最大值就可以只保留一个在序列开头,其余的放到结尾即可。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
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]);
vector<int> v;
for(int i=n; i>=1; i--){
if(a[i] == a[n] && i != n) continue;
v.push_back(a[i]);
}
for(int i=n; i>=1; i--){
if(a[i] == a[n] && i != n) v.push_back(a[i]);
}
bool flag = true;
int sum = 0;
for(int i=0; i<(int)v.size(); i++){
if(v[i] == sum) flag = false;
sum += v[i];
}
if(flag){
printf("YES\n");
for(int i=0; i<(int)v.size(); i++) printf("%d ",v[i]);
printf("\n");
}
else printf("NO\n");
}
return 0;
}

B.Matrix of Differences

题目描述:

对于一个 \(n\times n\) 的矩阵,对于每一对相邻(有公共边)的值 \(a,b\),写下 \(|a-b|\)(即 \(a\) 与 \(b\) 差的绝对值)。定义这个矩阵的美丽度为写下的不同的值的个数。以如下的矩阵为例:

\[\left(\begin{matrix}1&3\\4&2\end{matrix}\right)
\]

则所有相邻值的绝对值分别是 \(|1-3|=2,|1-4|=3,|3-2|=1,|4-2|=2\)。共有 \(1,2,3\) 三种不同的值,则这个矩阵的美丽度为 \(3\)。

给你 \(t\) 次询问,每次询问给定一个正整数 \(n\)。输出任意一个 \(n\times n\) 的矩阵,满足 \(1\sim n^2\) 在矩阵中各出现一遍,并且该矩阵的美丽度最大。

\(1\le t\le49,2\le n\le50\)。

题目分析:

手摸了半天才搞出来的做法。

考虑 \(n-1\) 会怎么得到,只有可能是 \(1,n\),那 \(n-2\) 呢?

可以是 \(1,n-1\) 或者 \(2,n\),为了构造的漂亮程度我们就不妨将 \(n,n-1\) 放到 \(1\) 的旁边,然后 \(2\) 继续放到下面,也就是下面这种方式:

\[\begin{matrix}
1 &n-1 &4 &n-5 &\cdots\\
n &3 &n-4 &\cdots\\
2 &n-3 &\cdots\\
n-2 &\cdots\\
\cdots
\end{matrix}
\]

然后就可以过了。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 100;
int a[N][N];
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
int l = 1,r = n*n,tot = 0;
for(int i=1; i<=n; i++){
++tot;
int nx = i,ny = 1;
while(nx >= 1 && ny <= n){
if(tot & 1) a[nx][ny] = l,l++;
else a[nx][ny] = r,--r;
nx --,ny ++;
}
}
for(int i=2; i<=n; i++){
++tot;
int nx = n,ny = i;
while(nx >= 1 && ny <= n){
if(tot & 1) a[nx][ny] = l,l++;
else a[nx][ny] = r,--r;
nx --,ny ++;
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
printf("%d ",a[i][j]);
}
printf("\n");
}
}
return 0;
}

C.Yet Another Tournament

题目描述:

有 \(n\) 个选手,编号为 \(1\) 至 \(n\) ,每两个选手对战时,编号大的将会胜利。

你可以准备 \(m\) 单位时间,每准备 \(a_i\) 时间就可以赢 \(i\) 号选手。

按胜利的总次数排名,求你最高多少名。

题目分析:

一个想法就是我们直接将 \(a\) 最小到大排序,这样就可以赢尽可能多的场,看上去就是很好的排名。

但是我们的排名还与我们赢了哪些人有关,所以就有点不可做的样子。

注意到,当我们赢了 \(x\) 场就相当于要选择 \(n-x\) 个人多赢一场,然后寻找赢场数大于 \(x\) 的人的个数,而只有赢场数等于 \(x\) 的人会受到我们选择加一的影响,所以其实此时只需要判断能不能通过调整使得我们可以赢过胜场为 \(x\) 的人即可。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5+5;
int a[N],b[N];
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%lld",&T);
while(T--){
int n,m;scanf("%lld%lld",&n,&m);
for(int i=1; i<=n; i++) scanf("%lld",&a[i]),b[i] = a[i];
sort(b+1,b+n+1);
int pos = 0;
for(int i=1; i<=n; i++){
if(m - b[i] >= 0){
pos = i;
m -= b[i];
}
}
if(!pos){
printf("%lld\n",n+1);
continue;
}
if(pos != n && a[pos+1] <= m + b[pos]) ++pos;
printf("%lld\n",n-pos + 1);
}
return 0;
}

D.Different Arrays

题目描述:

给你一个有 \(n\) 个元素的序列,你需要进行 \(n-2\) 次操作。

对于第 \(i\) 次操作,你可以选择让 \(a_i-a_{i+1}\) 且 \(a_{i+2}+a_{i+1}\) 或者可以选择让 \(a_i+a_{i+1}\) 且 \(a_{i+2}-a_{i+1}\)

问最后能产生多少个不同的序列。

题目分析:

一个想法就是判断什么样的序列是能被表示的,但是想了一会发现根本没有任何头绪,所以考虑换个想法,也就是直接使用 \(dp\) 去决策每一次的操作。

为了方便理解,我们将第 \(i\) 次操作,成为操作第 \(i+1\) 个数。

但是这样看上去有很多重复的情况就很难办,注意一点就是要使得产生相同的序列则必然满足存在 \(a_i = 0\) 的情况,然后操作 \(a_i\),否则一定不会产生相同的情况,所以我们完全不用考虑什么去重之类的问题,只需要判断 \(a_i = 0\) 即可。

所以可以考虑设 \(dp_{i,j}\) 表示操作完了前 \(i\) 个数,\(a_{i+1} = j\) 的方案数,记第二维的原因是我们此时需要决策第 \(i+1\) 次操作就必须知道对应的 \(a\) 是什么。

转移就是显然的,也就是直接枚举 \(a_{i+1}\) 是怎么操作的,以及特判 \(a_{i+1} = 0\)。

注意到第二维可以为负,所以加一个偏移量。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int MAX = 90000;
int dp[305][90005 * 2];
int a[305];
void add(int &a,int b){
a = (a + b)%MOD;
}
int main(){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
dp[1][MAX+a[2]] = 1;
for(int i=1; i<n; i++){
for(int k=-MAX; k<=MAX; k++){
if(!dp[i][k+MAX]) continue;
if(k == 0){
dp[i+1][a[i+2]+MAX] = (dp[i+1][a[i+2]+MAX] + dp[i][k+MAX])%MOD;
}
else{
dp[i+1][a[i+2]+k+MAX] = (dp[i+1][a[i+2]+k+MAX] + dp[i][k+MAX])%MOD;
dp[i+1][a[i+2]-k+MAX] = (dp[i+1][a[i+2]-k+MAX] + dp[i][k+MAX])%MOD;
}
}
}
int ans = 0;
for(int j=-MAX; j<=MAX; j++) add(ans,dp[n-1][j+MAX]);
printf("%d\n",ans);
return 0;
}

E.Game of the Year

题目描述:

Monocarp 和 Polycarp 正在玩电脑游戏。游戏特点:$ n $ 个编号从 $ 1 $ 到 $ n $ 的BOSS。

他俩将用以下方式与BOSS战斗

  • Monocarp 进行 $ k $ 次尝试撒掉boss;
  • Polycarp 进行 $ k $ 次尝试撒掉boss;
  • Monocarp 进行 $ k $ 次尝试撒掉boss;
  • Polycarp 进行 $ k $ 次尝试撒掉boss;
  • ...

Monocarp 在第 $ a_i $ 次尝试中撒掉了第 $ i $ 只BOSS。Polycarp 在第 $ b_i $ 次尝试中撒掉了第 $ i $ 只BOSS。其中一个人撒掉第 $ i $ 只BOSS后,他们就会尝试撒第 $ (i+1) $ 只BOSS。并且他们的尝试计数器都会清空。撒掉第 $ n $ 只BOSS后,游戏结束。

找到从$ 1 $ 到 $ n $所有的 $ k $ 值, 使得 Monocarp 可以杀死所有的BOSS。

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

题目分析:

题目说的实在是太抽象了,转化一下题意就是要找到满足以下条件的 \(k\):

\[\begin{aligned}
&\forall i\in[1,n] & \lceil \frac{a_i}{k} \rceil \le \lceil \frac{b_i}{k} \rceil
\end{aligned}
\]

首先就是可以直接整除分块就能找到所有满足条件的 \(k\),复杂度 \(O(n\sqrt{n})\) 但是常数有点逆天据说不能过,考虑优化。

一个经典的想法就是既然不能枚举约数,那么我们就枚举倍数,即枚举 \(k\) 然后枚举 \(k\) 的倍数。

可以发现 \(k\) 的倍数将序列分成了 \(O(\frac{n}{k})\) 段,而要使得上述条件满足就是 \(a_i\) 所在的块不在 \(b_i\) 所在的块后面。

如果原来就满足 \(a_i \le b_i\) 则无论如何都满足条件,就不管了。

如果 \(a_i > b_i\) 条件其实就是 \(a_i\) 所在的块与 \(b_i\) 所在的块相同,这个不是很好判,那么什么时候是不在一块呢?

既然不在一块也就是说 \([b_i,a_i]\) 跨过了一个分界点,如果我们以 \(k\) 的倍数作为每一段的右端点,也就是 \([b_i,a_i)\) 包含 \(k\) 的倍数。

可以直接预处理出每一个位置是否可以作为右端点,然后对于每一个 \(k\) 的倍数判断一下即可。

复杂度 \(O(n \log n)\)

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+5;
int a[N],b[N],sum[N];
vector<int> v;
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) scanf("%d",&b[i]);
for(int i=1; i<=n; i++){
if(a[i] > b[i]) sum[b[i]]++,sum[a[i]]--;
}
for(int i=1; i<=n; i++) sum[i] += sum[i-1];
for(int i=1; i<=n; i++){
bool flag = true;
for(int j=i; j<=n; j+=i){
if(sum[j]) flag = false;
}
if(flag) v.push_back(i);
}
printf("%d\n",v.size());
for(int i=0; i<v.size(); i++) printf("%d ",v[i]);
printf("\n");
for(int i=0; i<=n; i++) sum[i] = 0;
v.clear();
}
return 0;
}

F.Double Sort II

题目描述:

有两个 \(1..n\) 的排列 \(a,b\)。

你可以进行若干次操作,每次操作流程如下:

  • 选择一个整数 \(i \in [1,n]\)。

  • 找出两个整数 \(x,y\),使得 \(a_x=b_y=i\)。

  • 交换 \(a_x\) 和 \(a_i\),以及 \(b_y\) 和 \(b_i\)。

问把 \(a\) 和 \(b\) 从小到大排序的最小操作次数

题目分析:

考虑将排列看作一个置换,然后建图,也就是连边 \(i \to a_i\) 与 \(i \to b_i\),注意这是两张图。

我们的一次操作相当于将某个点缩成一个自环,其他点不受影响,所以对于每一个置换环设其长度为 \(len\) 只需要操作 \(len-1\) 次就可以将所有点缩成自环,即我们可以对于每一个环钦定一个点使得这个点不被操作,要最大化钦定点的数量。

而两张图其实也是差不多的,如果钦定 \(i\) 不被操作,也就是说 \(i\) 在 \(a,b\) 中的环上均只能选择 \(i\) 这一个点不被操作,这个其实就是一个匹配的感觉。

所以可以对于每一个点 \(i\),找到其在 \(a,b\) 上的环,将这两个环连边,最后跑一个最大匹配就是最多的不用被操作的点数。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
struct edge{
int nxt,to,id;
edge(){}
edge(int _nxt,int _to,int _id){
nxt = _nxt,to = _to,id = _id;
}
}e[2 * N];
int cnt,col1[N],col2[N],head[N],flag[N],match[N],a[N],b[N];
bool vis[N],tag[N];
void add_edge(int from,int to,int id){
e[++cnt] = edge(head[from],to,id);
head[from] = cnt;
}
bool dfs(int now){
if(vis[now]) return false;
vis[now] = true;
for(int i=head[now] ;i ; i=e[i].nxt){
int to = e[i].to;
if(!match[to] || dfs(match[to])){
match[now] = to,match[to] = now;
flag[now] = flag[to] = e[i].id;
return true;
}
}
return false;
}
void dfs1(int now,int col){
if(col1[now]) return;
col1[now] = col;
if(!col1[a[now]]) dfs1(a[now],col);
}
void dfs2(int now,int col){
if(col2[now]) return;
col2[now] = col;
if(!col2[b[now]]) dfs2(b[now],col);
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n;scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) scanf("%d",&b[i]);
int tot = 0;
for(int i=1; i<=n; i++){
if(col1[i]) continue;
++tot;dfs1(i,tot);
}
int tmp = tot;
memset(vis,false,sizeof(vis));
for(int i=1; i<=n; i++){
if(col2[i]) continue;
++tot;dfs2(i,tot);
}
for(int i=1; i<=n; i++){
add_edge(col1[i],col2[i],i);
add_edge(col2[i],col1[i],i);
// printf("%d %d\n",col1[i],col2[i]);
}
int ans = 0;
for(int i=1; i<=tmp; i++){
memset(vis,false,sizeof(vis));
ans += dfs(i);
}
printf("%d\n",n - ans);
for(int i=1; i<=tmp; i++){
tag[flag[i]] = true;
}
for(int i=1; i<=n; i++){
if(!tag[i]) printf("%d ",i);
}
return 0;
}

G.Weighed Tree Radius

题目描述:

给你一个\(n\)个点的树和\(n-1\)条边。第\(i\)个点的初始权值为\(a_i\)。

定义结点\(v\)到结点\(u\)的距离\(d_v(u)\)等于\(v\)和\(u\)之间的边的数量。注意:\(d_v(u)=d_u(v),d_v(v)=0\)

定义结点\(v\)到结点\(u\)的权值距离\(w_v(u)=d_v(u)+a_u\)。注意:\(w_v(v)=a_v,w_v(u) \neq w_u(v)\)如果\(a_u \neq a_v\)

与通常的距离类似,让我们定义结点\(v\)的偏心距\(e(v)\)是从\(v\)到其他结点的最大权值距离(包括\(v\)本身),即\(e(v)=\max\limits_{1\leq u \leq n} w_v(u)\)。

最后,我们定义树的半径\(r\)是所有偏心距的最小值,即\(r=\min\limits_{1\leq v\leq n} e(v)\)

你需要对\(m\)次询问进行回答,对于第\(j\)次询问,给出两个数\(v_j\)和\(x_j\),表示将\(a_{v_j}\)的值修改为\(x_j\)。

在每次询问后,输出当前该树的半径\(r\)。

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

题目分析:

题目已经提示了这东西叫做半径,那么是不是直接求直径然后除以 \(2\) 就可以呢?

我们定义 \(w'(u,v) = a_u + a_v + dis(u,v)\),那么满足 \(w'(u,v)\) 最大的两个点 \(u,v\) 之间的路径的长度我们称为直径。

这里我们将 \(a_u\) 理解为挂在 \(u\) 上长度为 \(a_u\) 的链,\(a_v\) 理解为挂在 \(v\) 上长度为 \(a_v\) 的链。

设直径的中点为 \(mid\),若 \(mid\) 在直径的某一个节点上,则显然 \(r = \lceil \frac{w'(u,v)}{2} \rceil\),可是如果 \(mid\) 不在直径的某一个节点上呢。

若 \(mid\) 在 \(a_u\) 对应的链上,则必然满足 \(e_u = a_u\),则对于其它的任意一个点 \(x\) 都必然满足 \(e_x \ge dis(u,x) + a_u > a_u = e_u\),即 \(r = a_u\),但是这样的话就必然满足直径为 \(w'(u,u)\) 就不可能不存在了。

下面我们的问题就转化为了维护直径。

考虑假设我们原来的直径为 \((u,v)\) 现在将 \(a_x\) 增大了一些,那么我们新直径的端点必然是 \(u,v,x\) 其中的两个,可以直接分类讨论得到答案。

而如果我们将 \(a_x\) 减小了一些,我们就无法判断直径端点的变化,所以可以考虑使用线段树分治维护修改,这样每次将值从 \(0\) 开始变化,这样每次都是加的操作了。

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

  1. Educational Codeforces Round 141 解题报告

    Educational Codeforces Round 141 解题报告 \(\text{By DaiRuiChen007}\) \(\text{Contest Link}\) A. Make it ...

  2. Educational Codeforces Round 141 (Rated for Div. 2) A-E

    比赛链接 A 题意 给一个数组 \(a\) ,要求重排列以后 \(a[i] \neq a[1,i-1]\) ,其中 \(a[1,i-1]\) 是前 \(i-1\) 项和. 如果无解则输出 NO :否则 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  10. Educational Codeforces Round 64 部分题解

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

随机推荐

  1. MassTransit类库Saga文档翻译

    翻译自 Saga State Machines Saga State Machines(状态机) Saga State Machines(状态机)以前被称为Automatonymous,从v8开始被合 ...

  2. error: #20: identifier "arm_cfft_instance_f64" is undefined

    在使用Keil5的过程中,偶尔遇到这个问题,以及类似的问题,报错的数量大概200多个. error type>(42): error: #20: identifier "arm_cff ...

  3. 公路堵车概率模型Python(Nagel-Schreckenberg交通流模型)

    路面上有N辆车,以不同速度向前行驶,模拟堵车问题.有以下假设: 假设某辆车的当前速度是 v 如果 前方可见范围内没车,下一秒车速提高到 v+1 如果 前方有车,前车的距离为 d ,且 d < v ...

  4. 推荐一个 C#写的 支持OCR的免费通用扫描仪软件

    NAPS2是一个开源免费软件,体积只有6M不到,支持运行在 Windows, Mac 和 Linux操作系统中,默认就带有简体中文界面,官方默认就提供绿色版,所以解压即可使用,直接可以从官方网站下载: ...

  5. Serverless云上作战阵型 | 通过云函数使用云数据库快速突破音障

    随着航空塔台的指令在耳边响起,飞行员奔向此次作战行动的两架座机.雷厉风行的爬进驾驶舱,关上舱盖,迅速下载简化操作的Demo包到机载电脑,从容的打开发动机,驾驶战斗机缓缓滑入跑道,后面僚机也已准备就绪. ...

  6. 了解基于模型的元学习:Learning to Learn优化策略和Meta-Learner LSTM

    摘要:本文主要为大家讲解基于模型的元学习中的Learning to Learn优化策略和Meta-Learner LSTM. 本文分享自华为云社区<深度学习应用篇-元学习[16]:基于模型的元学 ...

  7. CMU15445 (Fall 2020) 数据库系统 Project#4 - Concurrency Control 详解

    前言 一个合格的事务处理系统,应该具备四个性质:原子性(atomicity).一致性(consistency).隔离性(isolation)和持久性(durability).隔离性保证了一个活跃的事务 ...

  8. Python与TensorFlow:如何高效地构建和训练机器学习模型

    目录 标题:<Python 与 TensorFlow:如何高效地构建和训练机器学习模型> 一.引言 随着人工智能的快速发展,机器学习作为其中的一个重要分支,受到了越来越多的关注和应用.而P ...

  9. 万字长文解析最常见的数据库恢复算法: ARIES

    万字长文解析最常见的数据库恢复算法: ARIES 首发地址: https://mp.weixin.qq.com/s/Kc13g8OHK1h_f7eMlnl4Aw Introduction 上图中为基于 ...

  10. 1.3 Metasploit 生成SSL加密载荷

    在本节中,我们将介绍如何通过使用Metasploit生成加密载荷,以隐藏网络特征.前一章节我们已经通过Metasploit生成了一段明文的ShellCode,但明文的网络传输存在安全隐患,因此本节将介 ...