Educational Codeforces Round 143 (Rated for Div
Educational Codeforces Round 143 (Rated for Div. 2)
Problem - B Ideal Point
给定n个线段区间\([l,r]\),我们定义\(f(x)\)为覆盖点\(x\)的线段数,我们每次操作可以删除任意一条线段,并且操作数不限,给出q次询问,每次询问点x能否通过操作使得\(f(x)\)严格最大
题解:贪心
我们通过模拟发现只要把不包含x的线段全部删除,那么仍然存在的线段都会限制\(f(x)\),然后如果存在其他点y使得\(f(y)>=f(x)\)或者存在,那么说明我们无论如何都不能使得\(f(x)\)最大,反之一定可以,由于数据比较小,直接通过计数数组\(cnt\)判断即可
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10;
int n, k;
pii a[55];
void solve()
{
cin >> n >> k;
for (int i = 1; i <= n; ++i)
cin >> a[i].first >> a[i].second;
vector<int> cnt(55, 0);
int ok = 0;
for (int i = 1; i <= n; ++i)
{
if (a[i].first <= k && k <= a[i].second)
{
for (int j = a[i].first; j <= a[i].second; ++j)
cnt[j]++;
}
}
int maxx = -INF, num = 0;
for (int i = 1; i <= 50; ++i)
maxx = max(cnt[i], maxx);
for (int i = 1; i <= 50; ++i)
if (cnt[i] == maxx)
num++;
if (cnt[k] == maxx && num == 1)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
Problem - C Tea Tasting
给定n杯茶,每杯茶有\(a_i\)毫升,每杯茶面前都有一个品茶人,每次能够喝\(b_i\)毫升的茶,每一轮品茶结束后所有人都会往左移动,也就是说第一回合结束后第一个人不会再喝茶,第二回合结束后第二个人不会再喝茶,那么每个人在每回合能够喝到茶的数量为\(min(a_i,b_i)\),请你求出所有人分别能够喝到的茶的数量
题解:二分+前缀和+差分
首先我们可以知道对于第\(i\)杯茶来说,只有\([i+1,n]\)这些人能够喝到,所以我们可以先求出每个人喝茶\(b_i\)的前缀和\(pre\),对于每杯茶我们只需要二分前缀和找到后面第一个喝不满\(b_j\)这个茶的人\(j\),那么我们只要让\(j\)喝完剩下所有茶,然后利用差分数组记录中间都能喝满自己能喝的茶的人即可;
注意:这边在二分前缀和的时候有个技巧,我们对于每个\(a_i\)都要去往\(i\)的后面找,也就是说所有\(i\)后面的前缀和都要减去\(pre[i-1]\),比较麻烦,那么我们这边大佬有个技巧就是我们直接\(a_i+pre[i-1]\),这样效果也是一样,我只能说太秀
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10;
int n;
int pre[N];
void solve()
{
cin >> n;
vector<int> ans(n + 10);
vector<int> a(n + 10), b(n + 10);
vector<int> dif(n + 10);
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = 1; i <= n; ++i)
cin >> b[i];
for (int i = 1; i <= n; ++i)
pre[i] = pre[i - 1] + b[i];
for (int i = 1; i <= n; ++i)
{
int pos = upper_bound(pre + 1, pre + n + 1, a[i] + pre[i - 1]) - pre;
ans[pos] += a[i] - (pre[pos - 1] - pre[i - 1]);
dif[i]++;
dif[pos]--;
}
for (int i = 1; i <= n; ++i)
dif[i] = dif[i - 1] + dif[i];
for (int i = 1; i <= n; ++i)
{
ans[i] += b[i] * dif[i];
cout << ans[i] << " ";
}
cout << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
Problem - D Triangle Coloring
给定n个节点和n条边,每条边存在权值,并且\(6|n\),将每三个节点变成一个三元组,并用三条边连接,现在需要将n个点中一半的点涂成红色,一半的点涂成蓝色,如果两个点颜色不一样,那么连接这两个点的边的权值会被记录在sum中,最后你需要使得sum最大,并且求出使得sum最大的方案数
题解:组合计数+思维
首先n个点中一半为红色,一半为蓝色,很明显在一个三元组内,我们只有两种涂色方式:
- 全为红色或蓝色;
- 一红二蓝或者一蓝二红;
显然后者对于sum的贡献更大,我们取后者
假设一个三元组需要涂一红二蓝,也就是说我们在每个三元组中会选择两条边,那么存在以下几种情况:
- 每条边的权值都不一样,我们肯定会选择最大的两条,那么只有一种选择
- 最小两条边的权值相同,那么我们肯定会选择最大的以及任意一条最小边,有两种选择;
- 如果三条边的权值都相同,我们任意选择两条边即可,有3种选择;
那儿我们还需要知道哪些三元组涂了一红二蓝,哪些涂了一蓝二红,答案乘上\(C_{n/3}^{n/6}\)即可
注意:因为取模运算没有除法,所以我们需要利用快速幂求出乘法逆元,\(C_{n/3}^{n/6} = \frac{A_{n/3}^{n/6}}{A_{n/6}^{n/6}}\)
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-9;
const int N = 3e5 + 10, M = 4e5 + 10;
int qpow(int x, int y)
{
int res = 1;
while (y)
{
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int A(int n, int m)
{
int res = 1;
for (int i = m; i > m - n; --i)
res = res * i % mod;
return res;
}
int n;
int a[4];
void solve()
{
cin >> n;
int ans = 1;
for (int i = 1; i <= n; i += 3)
{
cin >> a[1] >> a[2] >> a[3];
sort(a + 1, a + 4);
if (a[1] == a[2] && a[2] == a[3])
ans = ans * 3 % mod;
else if (a[1] == a[2])
ans = ans * 2 % mod;
}
ans = ans * A(n / 6, n / 3) % mod;
ans = ans * qpow(A(n / 6, n / 6), mod - 2) % mod;
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}
Problem - E Explosions?
给定n个怪兽,每个怪兽血量为\(h_i\),你现在有两种魔法:
- 消耗1MP,对一个怪兽的血量减去1,可以释放无数次
- 消耗xMP,对于一个怪兽的血量减去x,如果该怪兽死亡,会引起连锁反应,他会对它相邻两边的怪兽产生爆炸伤害\(h_i-1\),如果该伤害继续造成死亡,会继续往旁边造成爆炸伤害,直到没有造成死亡为止,只能在最后一次释放
注意:怪物的位置不能移动,即使怪物死了,也不会消失
请你求出最少需要多少MP才能消灭所有怪物
题解:维护二元单调栈+贪心 :好题目
根据贪心思想,我们最好在最后一步爆炸解决掉所有的怪兽,所以我们可以枚举在每一个怪兽位置爆炸需要的MP,最后取min即可
那么为了实现最后的爆炸能够清除所有的怪兽,我们需要保证数组h要形成一个单峰,引爆位置左边严格递增,引爆位置右边严格递减,那么假设使得左边严格递增的花费为\(L[i]\),右边严格递减的花费为\(R[i]\),那么选择i位置作为引爆点的全部花费为\(L[i]+R[i]+h[i]\)
现在的关键就是如何求出L[i]和R[i],我们先对于L[i]进行讨论,R[i]可以同理得出:
我们可以维护一个单调递增栈,栈中元素是个二元组\((val,cnt)\)表示一个集合:val代表集合中最大值,cnt代表集合中有cnt个数,并且该集合是一个严格递增且差值为1的集合,那么很明显我们可以知道集合中的最小值为\(val-cnt+1\)
那么我们遍历数组\(h\)维护单调递增栈,我们讨论以下情况对单调栈内的集合进行合并和插入:
如果当前集合的最小值\(val-cnt+1>\)栈顶集合的最大值,直接将插入集合\((h[i],1)\)
如果当前集合的最小值\(val-cnt+1<=\)栈顶集合的最大值,那么我们需要将集合进行合并,合并的过程需要代价,并将栈顶不断出栈,直到不能合并为止,比如栈顶为(3,1),待插入的集合为(2,1),那么合并后的集合应该为(2,2),所以花费应该为3-2=1,因为我们需要的是一个单调递增且差值为1的集合
再举个例子,(3,3)和(3,2)合并,也就是(1,2,3)和(2,3)合并,那么我们需要的代价就是为了方便先把(1,2,3)变为(0,0,0)然后再变成(0,0,1),所以需要的代价为(1+2+3-1),那么这个代价我们可以利用等差数列求和快速实现
根据这样的操作我们就能够计算出L[i],同理我们从后往前遍历维护单调递增栈,即可求出\(R[i]\)
下面给出一个样例,并附上图示,便于理解集合的合并和为什么这样能够得出L[i]和R[i]:
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 3e5 + 10, M = 4e5 + 10;
int n;
pii stk[N];
int h[N], L[N], R[N];
int tt;
int cal(int x, int n)
{
int p = max(0ll, x - n + 1);
return n * (p + x) / 2;
}
void solve()
{
cin >> n;
tt = 0;
for (int i = 1; i <= n; ++i)
cin >> h[i];
int sum = 0;
for (int i = 1; i <= n; ++i)
{
int cnt = 1;
while (tt && h[i] - cnt + 1 <= stk[tt].first)
{
int minn = max(0ll, h[i] - cnt + 1); //防止最小值为负数
sum += cal(stk[tt].first, min(stk[tt].first, stk[tt].second));
sum -= cal(max(0ll, minn - 1), min(max(0ll, minn - 1), stk[tt].second));
cnt += stk[tt].second;
tt--;
}
L[i] = sum;
stk[++tt] = mpk(h[i], cnt);
}
tt = 0;
sum = 0;
for (int i = n; i >= 1; --i)
{
int cnt = 1;
while (tt && h[i] - cnt + 1 <= stk[tt].first)
{
int minn = max(0ll, h[i] - cnt + 1);
sum += cal(stk[tt].first, min(stk[tt].first, stk[tt].second));
sum -= cal(max(0ll, minn - 1), min(max(0ll, minn - 1), stk[tt].second));
cnt += stk[tt].second;
tt--;
}
R[i] = sum;
stk[++tt] = mpk(h[i], cnt);
}
int ans = INF;
for (int i = 1; i <= n; ++i)
ans = min(ans, h[i] + L[i] + R[i]);
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
Educational Codeforces Round 143 (Rated for Div的更多相关文章
- Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship
Problem Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship Time Limit: 2000 mSec P ...
- Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems(动态规划+矩阵快速幂)
Problem Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems Time Limit: 3000 mSec P ...
- Educational Codeforces Round 43 (Rated for Div. 2)
Educational Codeforces Round 43 (Rated for Div. 2) https://codeforces.com/contest/976 A #include< ...
- Educational Codeforces Round 35 (Rated for Div. 2)
Educational Codeforces Round 35 (Rated for Div. 2) https://codeforces.com/contest/911 A 模拟 #include& ...
- Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings
Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings 题目连接: http://cod ...
- Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes
Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://code ...
- Educational Codeforces Round 63 (Rated for Div. 2) 题解
Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...
- Educational Codeforces Round 39 (Rated for Div. 2) G
Educational Codeforces Round 39 (Rated for Div. 2) G 题意: 给一个序列\(a_i(1 <= a_i <= 10^{9}),2 < ...
- Educational Codeforces Round 48 (Rated for Div. 2) CD题解
Educational Codeforces Round 48 (Rated for Div. 2) C. Vasya And The Mushrooms 题目链接:https://codeforce ...
- Educational Codeforces Round 60 (Rated for Div. 2) 题解
Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...
随机推荐
- Windows下x86和x64平台的Inline Hook介绍
前言 我在之前研究文明6的联网机制并试图用Hook技术来拦截socket函数的时候,熟悉了简单的Inline Hook方法,但是由于之前的方法存在缺陷,所以进行了深入的研究,总结出了一些有关Windo ...
- 编写FailServlet和SuccessServlet类
@WebServlet("/successServlet") public class SuccessServlet extends HttpServlet { protected ...
- 解决VS2019 DevExpress工具不显示问题
一.序言 环境:NetFramework4.5,vs2019社区板 ,DevExpress 14.2.3 项目类型:winfrom 二.解决 找到DevExpress安装路径下的Bin\Framewo ...
- RxJava 异常时堆栈显示不正确?解决方法都在这里
本文首发我的博客,github 地址 大家好,我是徐公,今天为大家带来的是 RxJava 的一个血案,一行代码 return null 引发的. 前阵子,组内的同事反馈说 RxJava 在 debug ...
- 【vite】踩坑,首次点击路由跳转页面,发生回退,页面闪回,二次点击才能进入目标页面
[vite]踩坑,首次点击路由跳转页面,发生回退,页面闪回,二次点击才能进入目标页面 最近在做移动端前端项目,使用的vite3+vue3+vant,组件和api挂载,使用的自动导入,unplugin- ...
- JZOJ 2474. 【GDKOI 2021普及组DAY2】我的世界
题解 这题很明显发现一个点到另一个点,必然最多只有一个进入下界的点和一个出来的点 分类讨论入点和出点的位置 要么都在 \(u->lca\) 或都在 \(lca->v\) 或分别有一个 那就 ...
- ubuntu lnmp环境搭建 LNMP(Ubuntu 20.04 + Nginx + PHP 7.1 + Mysql5.7)
转载csdn: ubuntu lnmp环境搭建 LNMP(Ubuntu 20.04 + Nginx + PHP 7.1 + Mysql5.7)_ts3211的博客-CSDN博客_lnmp环境搭建
- 跳板攻击之:Netsh端口代理转发
跳板攻击之:Netsh端口代理转发 目录 跳板攻击之:Netsh端口代理转发 1 命令解析 2 代理转发内网22端口 3 代理转发外网4444端口 4 注意 1 命令解析 netsh interfac ...
- 基于JavaScript的OpenGL 01 之Hello Triangle
1. 引言 本文基于JavaScript语言,描述OpenGL(即,WebGL)的绘制流程,这里描述的是OpenGL的核心模式(Core-profile) 笔者这里不过多描述每个名词.函数和细节,更详 ...
- 【linux系统安装】Anolis OS-龙蜥操作系统实机安装流程整理
[安装准备] 1.准备一个U盘,可储存空间不低于20G,U盘内资料移出去,待会儿要格式化做U盘启动盘 2.windows操作系统上下载"Rufus",官网:http://rufus ...