A. Shifting Stacks

题目链接

点我跳转

题目大意

给定 \(N\) 个土堆,第 \(i\) 个土堆有 \(Ai\) 个木块

你可以将第 \(i\) 个土堆的木块转移至第 \(i + 1\) 个土堆

问能否使土堆的木块数量构成上升序列

解题思路

贪心

最优的构造方法即令土堆的木块数一次为 $0 , 1 , 2 , 3 ... $

定义 \(sum[i]\) 为 \(ai\) 的前缀和,那么只要判断是否每个前缀和都满足 \(sum[i] >= (i - 1) × i / 2\)

AC_Code

#include<bits/stdc++.h>

#define int long long

using namespace std;

const int N = 1e2 + 10;

int n , a[N] , sum[N];

signed main()
{
int T = 1; cin >> T; while(T --)
{
cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> a[i] , sum[i] = sum[i - 1] + a[i]; bool ok = true; for(int i = 1 ; i <= n ; i ++)
{
if(sum[i] - (i - 1) * i / 2 < 0) {
ok = false ; break ;
}
} if(ok) cout << "YES\n"; else cout << "NO\n";
} return 0;
}#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1e2 + 10; int n , a[N] , sum[N]; signed main()
{
int T = 1; cin >> T; while(T --)
{
cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> a[i] , sum[i] = sum[i - 1] + a[i]; bool ok = true; for(int i = 1 ; i <= n ; i ++)
{
if(sum[i] - (i - 1) * i / 2 < 0) {
ok = false ; break ;
}
} if(ok) cout << "YES\n"; else cout << "NO\n";
} return 0;
}

B. Eastern Exhibition

题目链接

点我跳转

题目大意

二维平面上给定 \(n\) 个点,问存在多少个整数坐标点使得这些点到 \(n\) 个点的曼哈顿距离总和最小

解题思路

如果是一维直线,那么这些点只会存在于横坐标 \(x\) 的中位数之间,或者纵坐标 \(y\) 的中位数之间

那么满足条件的点个数即为 横坐标 \(x\) 的中位数之间的长度 或 纵坐标 \(y\) 的中位数之间的长度

拓展到二维这些点的个数即为横坐标 \(x\) 的中位数之间的长度 \(×\) 纵坐标 \(y\) 的中位数之间的长度

当 \(n\) 为奇数时,\(x\) 的中位数只有 \(1\) 个,\(y\) 的中位数只有 \(1\) 个,所以答案为 \(1\)

当 \(n\) 为偶数时,答案即是 \(x\) 的中位数之间的长度 \(×\) \(y\) 的中位数之间的长度

AC_Code

#include<bits/stdc++.h>

#define int long long

using namespace std;

const int N = 1e3 + 10;

int n , x[N] , y[N];

signed main()
{
int T = 1; cin >> T; while(T --)
{
cin >> n; for(int i = 1 ; i <= n ; i ++) cin >> x[i] >> y[i]; sort(x + 1 , x + 1 + n) , sort(y + 1 , y + 1 + n); if(n & 1) cout << 1 << '\n'; else cout << (x[n / 2 + 1] - x[n / 2] + 1) * (y[n / 2 + 1] - y[n / 2] + 1) << '\n';
} return 0;
}

C1&C2.Guessing the Greatest

题目链接

点我跳转

题目大意

交互问题

有一个序列,每次你可以询问区间 \([L , R]\) 的次大值的位置

要求在 \(20\) 次询问内找出最大值的位置

解题思路

对于区间 \([L , R]\) 的次大值位置为 \(pos\)

那么最大值必然只出现在区间 \([L , pos - 1]\) 或区间 \([pos + 1 , R]\)

于是可以再次询问区间 \([L , pos]\) 的次大值位置判断最大值是位于区间 \([L , pos-1]\) 还是区间 \([pos +1 , R]\)

当 \(query([L , pos]) = pos\) , 且 \(pos != 1\) 时,最大值处于区间 \([L , pos - 1]\)

此时可以令 \(R = pos - 1\) , 并二分最大值的位置 \(mid\)

如果 \(query([mid , pos]) = pos\) ,则可以确定最大值位于区间 \([mid , pos]\) , 于是舍弃 \([l , mid - 1]\)

否则可以确定最大值不位于区间 \([mid , pos]\) , 于是二分的区间改为 \([l , mid - 1]\)

否则最大值位于区间 \([pos +1 , R]\) , 操作大致同上

AC_Code

#include<bits/stdc++.h> 

using namespace std;

int n , x;

int query(int l , int r)
{
cout << "? " << l << " " << r << '\n'; cin >> x; return x;
}
signed main()
{ cin >> n; int l = 1 , r = n , res = 0; int pos = query(1 , n); if(pos != 1 && query(1 , pos) == pos)
{
l = 1 , r = pos - 1; while(l <= r)
{
int mid = l + r >> 1; if(query(mid , pos) == pos) res = mid , l = mid + 1; else r = mid - 1;
} }
else
{
l = pos + 1 , r = n; while(l <= r)
{
int mid = l + r >> 1; if(query(pos , mid) == pos) res = mid , r = mid - 1; else l = mid + 1;
}
} cout << "! " << res << '\n'; return 0;
}

D. Max Median

题目链接

点我跳转

题目大意

给定一个序列,要求选出一个长度大于等于 \(k\) 的连续子序列

使得该序列的中位数最大

问最大中位数是多少?

解题思路

二分中位数 \(x\)

将序列中大于等于它的数变为 \(1\) ,小于它的数变为 \(0\)

假设选出的序列长度 \(len\) , 序列中 1 的个数为 \(cnt\)

那么当 \(cnt - 1 >= len / 2\) 时,返回 \(true\)

这里解释下两个问题 :

  1. 为什么式子左边是 \(cnt - 1\) 而不是 \(cnt\)?
  2. 为什么不是 \(cnt - 1 = len / 2\) 而是 \(cnt - 1 >= len / 2\)

q1. \(cnt - 1\) 是因为序列中的某个 \(1\) 得作为 x 本身

q2. 因为当 \(cnt - 1 > len / 2\) 时,必然存在一个大于 \(x\) 的数满足 \(cnt - 1 = len / 2\),所以需要返回 \(true\) 以向上改变二分区间

我们可以枚举区间右端点,并选定左端点以使式子的结果为 \(true\)

定义 \(sum[i]\) 为序列的前缀和,\(L\) 为当前区间的左端点 \(-1\) , \(R\) 为当前区间的右端点

那么 \(cnt = sum[R] - sum[L]\) , \(len = R - L\)

于是式子可以转变为 \(sum[R] - sum[L] - 1 >= (R - L) / 2\)

通过移项 ,式子可变为 \(2 × sum[R] - R - 2 >= 2 × sum[L] - L\)

因为 \(R\) 是我们枚举的 , 所以 \(R、sum[R]\) 都可认为常数

为了让不等式成立,我们需要让不等号右边的式子尽可能小

所以我们要取 \(mi\) \(=\) \(min∑(2 * sum[i] - i) , i ∈[1 , i - k]\)

因为每枚举一个右端点,只会出现一个新的可以选择的左端点 \(i-k\)

所以 \(mi\) 对于每一个右端点只要 \(O1\) 就可以得到了

注意:

得到了 \(mi\) 我们不能直接改写式子为 \(2 × sum[R] - R - 2 >= mi\)

因为 \((4 - 1) / 2 = 1\) 而不是 \(1.5\)

所以我们还要维护两个变量分别代表 \(sum[L]\) 和 \(L\)

AC_Code

#include<bits/stdc++.h>

using namespace std;

const int N = 3e5 + 10;

int n , m , k , a[N] , b[N] , sum[N];

bool check(int x)
{
int mi = 1e9 , pre = 1e9 , pos = -1e9; for(int i = 1 ; i <= n ; i ++)
{
if(a[i] >= x) b[i] = 1; else b[i] = 0; sum[i] = sum[i - 1] + b[i]; if(i - k >= 0 && mi >= 2 * sum[i - k] - (i - k))
{
mi = 2 * sum[i - k] - (i - k);
pos = i - k;
pre = sum[i - k];
} if(sum[i] - pre - 1 >= (i - pos) / 2) return true;
}
return false;
} signed main()
{
cin >> n >> k ; for(int i = 1 ; i <= n ; i ++) cin >> a[i]; int l = 1 , r = n , res = 0; while(l <= r)
{
int mid = l + r >> 1; if(check(mid)) l = mid + 1 , res = mid; else r = mid - 1;
} cout << res << '\n'; return 0;
}

E. Paired Payment

题目链接

点我跳转

题目大意

给定一张包含 \(N\) 个点,\(M\) 条边的无向图,每条边都有它的权值 \(w\) \((1 <= w <= 50)\)

每次从一个节点出发,都必须走完两条边才能停下(中间经过的点不算到达过)

途中的花费为两条边权值的和的平方

问节点 \(1\) 出发到达每个点所需的最小花费分别为多少

解题思路

很多人用暴力的做法居然没有 \(fst\) ?这就很神奇 \(hhh\)

update: 大数据貌似在 \(fst\) 之后才加上

定义 \(ans[i]\) 表示从节点 \(1\) 出发到达节点 \(i\) 的最小花费

定义 \(dis[w][i]\) 表示从某个点 \(x\) 走了 一条权值为 w 的边 到达节点 \(i\) ,而 \(dis[w][i] = min(ans[x])\)

假设当前节点为 \(u\) , 它的相邻节点为 \(v\) , 它们之间的边权为 \(w\)

那么不难得到

dis[w][v] = min(dis[w][v] , ans[u]);
for(int j = 1 ; j <= 50 ; j ++) ans[v] = min(ans[v] , dis[j][u] + (j + w) * (j + w));

所以跑 \(dijkstra\) 时只要边权被更新我们就把该点入队

但是传统的 \(dijkstra\) 在一个点入队后就会被打上标记从此不能再入队了

而这里我们显然是需要一个点重复入队才能保证答案的最优

如果选择重复入队就会使得复杂度爆炸?那怎么办呢?

我们可以统计每个点入队的次数,当次数大于 \(50\) 时就不再入队

这样可行是因为 \(dis\) 是由 \(ans\) 更新 , \(ans\) 是由 \(ans\) 和 边权 更新

而边权最大只有 \(50\) , \(50\) 次入队足够让 \(ans\) 由所有的边权更新一遍了

AC_Code

#include<bits/stdc++.h>

using namespace std;

const int inf = 0x3f3f3f3f;

const int N = 2e5 + 10;

struct node{
int dis , pos;
bool operator <( const node &x )const{
return x.dis < dis;
}
}; struct Edge{
int to , w , nex;
}edge[N << 1]; int head[N], dis[51][N] , tot , vis[N] , n , m , s , ans[N]; inline void add_edge(int u , int v , int d)
{
edge[++ tot].w = d; edge[tot].to = v; edge[tot].nex = head[u]; head[u] = tot;
}
inline void dijkstra(int s)
{
for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= 50 ; j ++) ans[i] = dis[j][i] = inf; ans[s] = 0; priority_queue <node> que; que.push(node{0 , s}); while(!que.empty())
{
node tmp = que.top(); que.pop(); int u = tmp.pos , d = tmp.dis ; if(vis[u] > 50) continue; vis[u] ++; for(int i = head[u] ; i ; i = edge[i].nex)
{
int v = edge[i].to , w = edge[i].w; for(int j = 1 ; j <= 50 ; j ++)
{
int cost = dis[j][u] + (j + w) * (j + w); if(cost < ans[v])
{
ans[v] = cost; if(vis[v] <= 50) que.push(node{ans[v] , v});
}
} if(dis[w][v] > ans[u])
{
dis[w][v] = ans[u]; if(vis[v] <= 50) que.push(node{dis[w][v] , v});
}
}
}
}
signed main()
{
cin >> n >> m; for(int i = 1 ; i <= m ; i ++)
{
int u , v , w; cin >> u >> v >> w; add_edge(u , v , w); add_edge(v , u , w);
} dijkstra(1); for(int i = 1 ; i <= n ; i ++)
{
if(ans[i] == inf) ans[i] = -1; cout << ans[i] << " ";
} return 0;
}

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

  1. Codeforces Round #703 (Div. 2)__ B. Eastern Exhibition__ 纯纯的思维

    原题链接https://codeforces.com/contest/1486/problem/B 题目 解题思路 这是个思维题,  算是货仓选址的变式, 想要到达各个点距离最小,我们的目标可以化为先 ...

  2. 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 ...

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

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

  4. Codeforces Round #368 (Div. 2)

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

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

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

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

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

  7. 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 ...

  8. 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 ...

  9. Codeforces Round #371 (Div. 1)

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

随机推荐

  1. Spring boot AOP 记录请求日志

    如何将所有的通过url的请求参数以及返回结果都输出到日志中? 如果在controller的类中每个方法名都写一个log输出肯定是不明智的选择. 使用spring的AOP功能即可完成. 1. 在pom. ...

  2. IPSec 专题----转自华为文档

    参考链接:https://support.huawei.com/enterprise/zh/doc/EDOC1000122878?section=j004 IPSec 特性全景 1.介绍 由于IP报文 ...

  3. 一篇文章搞定Java注解^_^

    0.序言 自己写这些文章本来想着自己系统的整理下知识,将知识串起来,后面复习用,或者以后年龄大了,去教育机构呀,拿出自己整理的笔记,你看这人爱总结爱分享,文笔也还能看,方便找工作不是. 很开心的是,有 ...

  4. Flink-v1.12官方网站翻译-P001-Local Installation

    本地安装 按照以下几个步骤下载最新的稳定版本并开始使用. 第一步:下载 为了能够运行Flink,唯一的要求是安装了一个有效的Java 8或11.你可以通过以下命令检查Java的正确安装. java - ...

  5. 树的直径&树的重心

    树的直径 定义 那么树上最远的两个点,他们之间的距离,就被称之为树的直径. 树的直径的性质 1. 直径两端点一定是两个叶子节点. 2. 距离任意点最远的点一定是直径的一个端点,这个基于贪心求直径方法的 ...

  6. Codeforces 1364C - Ehab and Prefix MEXs

    题意:给1e5的数组a 保证 ai <= ai+1  ai<=i  求一个一样长的数组b 使得mex(b1,b2···bi) = ai QAQ:不知道为啥这1600分的题比赛时出不了 啊啊 ...

  7. Uva 10815 Andy's First Dictionary(字符串)

    题目链接:https://vjudge.net/problem/UVA-10815 题意 找出一段文本中的所有单词,以小写形式按照字典序输出. 思路 用空白符替换文本中所有非字母字符后再次读入. 代码 ...

  8. ZYB loves Xor I HDU - 5269 字典树

    题意: T组样例,给你n个数.你要找出来这n个数中任意两个数的二进制位中  最低位不同  的位置(假设是k),然后让所有2^k加起来就是结果 什么意思? 例如4 和 2 4的二进制是(100),2的二 ...

  9. constexpr 的来龙去脉

    constexpr 是什么? 关键字 constexpr (constant expression) 是在 C++11 中引入的,并且在 C++14 中进行了优化. constexpr 和 const ...

  10. XV6学习(14)Lab fs: File system

    代码在github上. 这次实验是要对文件系统修改,使其支持更大的文件以及符号链接,实验本身并不是很复杂.但文件系统可以说是XV6中最复杂的部分,整个文件系统包括了七层:文件描述符,路径名,目录,in ...