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. (十三)整合 SpringSecurity 框架,实现用户权限管理

    整合 SpringSecurity 框架,实现用户权限管理 1.Security简介 1.1 基础概念 1.2 核心API解读 2.SpringBoot整合SpringSecurity 2.1 流程描 ...

  2. SparkSql 数据类型转换

    SparkSql 数据类型转换 1.SparkSql数据类型 1.1数字类型 1.2复杂类型 2.Spark Sql数据类型和Scala数据类型对比 3.Spark Sql数据类型转换案例 3.1获取 ...

  3. Spring5源码,Spring DispatecherServlet的生命周期

    一.前端控制器模式 二.DispatcherServlet的执行链 三.DispatcherServlet 1.策略初始化 2.请求预处理 3.请求处理 4.视图解析 5.处理调度请求 - 视图渲染 ...

  4. UML实战总结——机房收费系统UML第一版部分图展

    距离机房收费系统已经过去了近2个月之久,如今的UML图才出来,从软件开发设计的逻辑上来讲这是顺序有问题的,不过,对于我们而言,而且是初次用面向对象的思想去设计和建模,就当是UML的一个实战练手的项目吧 ...

  5. 用鸿蒙开发AI应用(七)触摸屏控制LED

    [小年答谢,新春送礼]免费抽取1000元京东卡+更多新春好礼~查看详情>>> 目录:前言背景知识编译用户程序框架子系统基于AbilityKit开发的Ability总结 前言上一篇,我 ...

  6. windows10与linux进行ftp遇到550 Failed to change directory及553 Could not creat file

    第一个原因: 没有权限,可以使用带有l参数的ls命令来看文件或者目录的权限 ls -l 解决:给本地用户添加一个可写权限 chmod +w /home/student ##给对应的本地用户添加一个可写 ...

  7. JavaScript——三

    任务: 其中的"options = options || {}"就代表如果options是一个真的对象,就使用它,否则就给他默认值 在Node函数中: 函数中的this指向wind ...

  8. 踏上Revit二次开发之路 3 自己的工具按钮

    3 自己的工具按钮 上次的例子只能在"附加模块"→"外部工具"下运行,用作个人作品是没问题,如果打算搞个公司产品的话,估计BOSS是不会满意的.这次我来做一个直 ...

  9. read()、readline()、readlines() -- Python

    文本文件:readfile.txt 详细描述: read()                  #一次性读取文本中全部的内容,以字符串的形式返回结果 readline()           #只读取 ...

  10. 【Java】位操作符

    位运算符 java支持的位运算符有7个,分为两类:位逻辑运算和移位运算.位逻辑运算符包括按位取反(~).按位与(&).按位或(|)和按位异或(^)4种,.移位运算符包括左移(<<) ...