stral Reflection

在 \([1,n]\)上支持如下操作:

操作一:学习一个新的技能——清除 \([l,r]\)内所有的陨石

操作二:给定一个点集\(k\)代表陨石出现在这些位置,询问最少需要使用多少技能才能清除所有陨石(不能使用当前没有学习的技能)

共操作\(m\)次

\(\sum k \leq 1e5\)

\(m \leq 1e5\)

\(n \leq 1e5\)

题解:线段树 + 贪心

  • 容易看出一定是在线查询
  • 不管怎么样,最左边的陨石一定会被清除
  • 所以我们不妨从最左边开始清除尽量多的陨石,也就是说,我们需要找到\(l\)比当前陨石小的,且右端点\(r\)最大的区间,贪心的消除尽量多的陨石
  • 那么我们可以利用线段树维护区间最大值,支持单点修改和区间查询即可,每次执行操作一就在\(l\)处加上\(r\)即可,假设当前需要清除陨石的位置为\(p\),查询时直接查询\([1,p]\)中的最大值即可,最大值即为最远的右端点
  • 时间复杂度:\(O(m + \sum k) logn\)
#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 = 1e5 + 10, M = 4e5 + 10; int n, m;
struct info
{
int maxx;
}; struct node
{
info val;
} seg[N << 2]; info operator+(const info &a, const info &b)
{
info c;
c.maxx = max(a.maxx, b.maxx);
return c;
} void up(int id)
{
seg[id].val = seg[lson].val + seg[rson].val;
} void change(int id, int l, int r, int x, int val)
{
if (l == r)
{
seg[id].val.maxx = max(seg[id].val.maxx, val);
return;
}
int mid = l + r >> 1;
if (x <= mid)
change(lson, l, mid, x, val);
else
change(rson, mid + 1, r, x, val);
up(id);
} info query(int id, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
return seg[id].val;
int mid = l + r >> 1;
if (qr <= mid)
return query(lson, l, mid, ql, qr);
else if (ql > mid)
return query(rson, mid + 1, r, ql, qr);
else
return query(lson, l, mid, ql, qr) + query(rson, mid + 1, r, ql, qr);
} void solve()
{
cin >> n >> m;
while (m--)
{
int op, l, r, w, k;
cin >> op;
if (op == 1)
{
cin >> l >> r >> w;
change(1, 1, n, l, r);
}
else
{
cin >> k;
queue<int> q;
for (int i = 1; i <= k; ++i)
{
int x;
cin >> x;
q.push(x);
}
int ans = 0;
bool flag = true;
while (q.size())
{
int max_R = query(1, 1, n, 1, q.front()).maxx;
if (max_R < q.front())
{
flag = false;
break;
}
ans++;
while (q.size() && q.front() <= max_R)
q.pop();
}
if (flag)
cout << ans << endl;
else
cout << -1 << endl;
}
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

hivalric Blossom

有 \(n\) 个任务,你需要给每个任务指定一个优先级,之后你会按优先级递增的顺序完成这些任务。如果有两个任务优先级相同,你会先完成编号小的。现在有 \(m\) 对任务必须连续完成,你的目标是在满足这些限制的情况下,让不同优先级的数量尽可能少。

题解:思维

  • 容易发现根据题目的限制产生了许多链,我们的任务就是给这些链染色,即指定优先级
  • 首先同一条链上的点的颜色一定相同,被一条链框住的这些节点的颜色一定和该链颜色不同
  • 所以我们不妨维护一个初始拥有\(n\)种颜色的集合,提前预处理好每个点的前驱和后继
  • 如果该点是一条链的头节点,我们就从颜色集合中取出一个颜色,分配给链头,然后在集合中将该颜色删除
  • 如果该点既不是链头也不是链尾,那就染上和链头一样的颜色,因为记录了该点的前驱,所以染的颜色取前驱的颜色即可
  • 如果该点是一条链的链尾,染上前驱的颜色后将该颜色添加会颜色集合中
  • 时间复杂度:\(O(nlogn)\)
#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 = 1e5 + 10, M = 4e5 + 10; int n, m;
int L[N], R[N];
set<int> st;
int ans[N]; void solve()
{
cin >> n >> m;
for (int i = 1; i <= m; ++i)
{
int a, b;
cin >> a >> b;
L[b] = a;
R[a] = b;
}
for (int i = 1; i <= n; ++i)
st.insert(i);
for (int i = 1; i <= n; ++i)
{
if (!L[i])
{
ans[i] = *st.begin();
if (R[i])
st.erase(st.lower_bound(*st.begin()));
}
else
{
ans[i] = ans[L[i]];
if (!R[i])
st.insert(ans[i]);
}
}
for (int i = 1; i <= n; ++i)
cout << ans[i] << "\n "[i < n];
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

clipsing Star

\(n\) 轮游戏,每轮有 \(a_i\) 块钱。在一轮中,先手可以自己拿 \(b_i\) 块钱,给后手 \(a_i−b_i\) 块钱,然后交换先后手的概率为 \(\frac{b_i}{a_i}\),问最优策略下先手方与后手方总钱数之差的最大值。

题解:思维

  • 我们考虑最后\(n-1\)轮和第\(n\)轮的情况,想要钱数之差最大,先手要么不取\(a_{n-1}\),要么取
  • 所以在不考虑前面轮数的情况下,最后两轮钱数之差的最大值一定为\(| a_n-a_{n-1}|\)
  • 容易发现我们可以把最后两轮归结为钱数为\(| a_n-a_{n-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 = 1e6 + 10, M = 4e5 + 10; int n;
int a[N]; void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
for (int i = n; i >= 2; i--)
a[i - 1] = abs(a[i] - a[i - 1]);
cout << a[1] << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

andelion Knight

给定 \(01\) 序列 \(a,b\),对于 \(x∈[0,2n]\),询问有多少方案可以在 \(a\) 和 \(b\) 各选择一个前缀,使得两个前缀的长度之和为 \(x\) 且两个前缀的和相等。我们定义上面的方案数为\(f(x)\),请你求出所有的\(f(x),x∈[0,2n]\)

思维 + 差分

  • 我们不妨先预处理出序列\(b\)中所有前缀中每个数\(i\)的起始位置\(l_i\)和结束位置\(r_i\)
  • 然后遍历序列\(a\),求其前缀和\(pre_j\),如果序列\(b\)中存在相同的前缀和\(i\),那么\(f(l_i + j,r_i+j)\)之间的答案都要加上\(1\)
  • 对于区间加的操作可以使用差分数组/树状数组维护差分/线段树实现
  • 如果使用差分数组实现,时间复杂度为\(O(n)\)
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#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<double, double> pdd;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 4e5 + 10; int n;
int ans[N << 1];
int a[N], b[N];
int L[N], R[N];
int pre[N]; void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
L[i] = INF, R[i] = -INF;
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];
L[pre[i]] = min(L[pre[i]], i);
R[pre[i]] = max(R[pre[i]], i);
}
int sum = 0;
if (L[sum] != INF)
{
ans[L[sum]]++;
ans[R[sum] + 1]--;
}
for (int i = 1; i <= n; ++i)
{
sum += a[i];
if (L[sum] != INF)
{
ans[L[sum] + i]++;
ans[R[sum] + i + 1]--;
}
}
for (int i = 1; i <= 2 * n; ++i)
ans[i] = ans[i - 1] + ans[i];
for (int i = 0; i <= 2 * n; ++i)
cout << ans[i] << "\n "[i < 2 * n];
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

uvenile Galant

询问将两种给定形状拼接成一个指定长度的直角梯形的方案数。


题解:\(DP\) + 简单状态机模型

容易发现是简单\(dp\),并且是状态机模型

  • 状态表示:

    \(f[i][0/1/2]\)代表较短的边长度为\(i\)的时,\(0\)代表\(i\)右端是平的,\(1\)代表\(i\)右端尖角朝下,\(2\)代表\(i\)右端尖角朝上的方案数

  • 状态属性:数量

  • 状态转移:状态机模型如下

    状态转移方程不再赘述

  • 状态机入口:\(1 / 2\)

  • 状态初始:\(f[0][0] = 1,f[1][1] = 1,f[1][2] = 1\)

  • 状态机出口:\(2\)

  • 答案呈现:\(f[n-1][2]\)

#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 = 1e6 + 10, M = 4e5 + 10; int n;
int f[N][3]; void solve()
{
cin >> n;
f[0][0] = 1;
f[1][1] = 1;
f[1][2] = 1;
for (int i = 1; i <= n; ++i)
{
f[i][0] = (f[i - 2][1] % mod + f[i - 2][2] % mod) % mod;
f[i][1] = (f[i - 2][1] % mod + f[i - 1][0] % mod) % mod;
f[i][2] = (f[i - 1][0] % mod + f[i - 2][2] % mod) % mod;
}
cout << f[n - 1][2] << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

HEUCPC2021的更多相关文章

  1. Silverlight 用DependencyProperty 自定义ImageButton控件 定义属性

    为ImageButton自定义IconSource和Contents属性 xaml代码 <UserControl x:Class="SilverlightCreate.Silverli ...

随机推荐

  1. 万字长文全面详解现代C++智能指针:原理、应用和陷阱

    现代C++智能指针详解:原理.应用和陷阱 智能指针是C++11引入的新特性.本篇文章详细介绍了C++智能指针的原理.应用与陷阱,通过丰富的代码实例介绍了三种智能指针:std::unique_ptr.s ...

  2. CSS MASK

    首先看如下效果: 这种效果看起来很赞,可以做出很酷炫的交互,比如图上这种,还有一种就是引导页 经过我阅读作者的文章,原文地址. 发现其实只要使用两个核心CSS样式就能实现这个效果 分别为: 1. ba ...

  3. JS常见的API扩展形式(prototype、jquery、vue插件封装)以及怎样设计出易扩展的表单验证功能?

    常见的API扩展形式 prototype 比如我现在有一个需求,给定一个字符串,给方法传递一个参数为数字类型来确定当前字符串重复次数,例如: 'abc'.repeatStringNumTimes(3) ...

  4. HTML & CSS – 实战 RWD Image 响应式图片

    前言 之前写过 HTML & CSS – Responsive Image 响应式图片 (完整版), 里面解释了原理和一些具体做法, 但是并不是以真实场景作为例子带入. 由于 RWD Imag ...

  5. 十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明)

    十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明) @ 目录 十,Spring Boot 的内容协商的详细剖析(附+Debug调试说明) 1. 基本介绍 2. 准备工作 3. ...

  6. .NET 7+Angular 4 轻量级新零售进销存系统

    前言 给大家推荐一个专为新零售快消行业打造了一套高效的进销存管理系统. 系统不仅具备强大的库存管理功能,还集成了高性能的轻量级 POS 解决方案,确保页面加载速度极快,提供良好的用户体验. 项目介绍 ...

  7. codeforces 1931E

    题目链接 简介:对一些数字,余念安可以反转一个数字,齐夏将两个数字首尾相连变为一个数字.每个人都采取最优策略. 名单上只剩下一个号码.如果该整数不小于  10的m次方 ,则齐夏获胜.否则余念安就赢了. ...

  8. 离线安装MySQL

    离线安装mysql [下载地址](MySQL :: Download MySQL Community Server) 解压后依次执行如下命令 rpm -ivh mysql-community-comm ...

  9. 2022年9月中国数据库排行榜:榜眼、探花纷纷易主,AnalyticDB蝉联榜单十强

    夏去秋来清风至,榜首前三起涟漪. 2022年9月的 墨天轮中国数据库流行度排行榜火热出炉,相比上月新增两个数据库, 本月榜单前十名可以用一句话概括为:OceanBase新版发布先声夺人,达梦低调做事暂 ...

  10. Putty 远程 连接kali Linux拒绝访问 refused connection

    1. 设置  ssh 文件 crtl + alt + t 代开终端 输入命令: vim /etc/ssh/sshd_config 说明 : 使用 vim 编辑器编辑 ssh 文件 : 说明: 修改第3 ...