「HGOI#2019.4.19省选模拟赛」赛后总结
t1-Painting
这道题目比较简单,但是我比较弱就只是写了一个链表合并和区间DP。
别人的贪心吊打我的DP,嘤嘤嘤。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
namespace chhokmah {
#define N 100005
#define M 5005
int a[N], l[M], r[M], pos[N];
int n, m, cnt;
ll sum[M], f[M][M];
ll ans = 0;
ll calc(int cnt) {
for (int i = 1; i <= cnt; i ++) sum[i] += sum[i - 1];
for (int i = cnt; i; i --)
for (int j = i; j <= cnt; j ++)
f[i][j] = max(f[i][j - 1], f[i + 1][j]) + sum[j] - sum[i - 1];
return f[1][cnt];
}
void chhokmah() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++) r[a[i]] = i;
for (int i = n; i; i --) l[a[i]] = i;
for (int i = 1; i <= m; i ++) pos[l[i]] = i;
for (int i = 1; i <= n; i ++) {
if (pos[i]) {
int cnt = 0, x = i;
while (pos[x]) { int y = pos[x]; pos[x] = 0; sum[++ cnt] = r[y] - l[y] + 1; x = r[y] + 1; }
ans += calc(cnt);
}
}
cout << ans << endl;
} }
int main() { chhokmah::chhokmah(); return 0; }
t2-Path
很显然是一道期望\(DP\)。这一道题目还是\(Bluesky\)大佬教我做的,先%为敬。
考虑到最优的策略,一定是从当前算出期望概率较小的点来更新较大的点。
以下是\(BlueSky\)大佬的题解
考虑是按照最优策略进行移动,如果开放一条边且子节点不会使答案变劣,那么就一定会沿该边走向子节点,否则停留在原地。
假设对于点\(i\),不会使答案变劣的点数为\(degree_i\),那么意味着有\(degree_i\)种可能会移动,有\(m-degree_i\)种可能不移动。设点\(i\)走到\(n\)的期望距离为\(f_i\),则有
\[
\begin{array}{rrcl}
&\large f_i&\large =&\large \frac{\large\sum_{v\in son}f_v+(m-degree_i)f_i}{\large m}+1\\\\
\large \Rightarrow&\large mf_i&\large =&\large \sum_{v\in son}f_v+(m-degree_i)f_i+m\\\\
\large \Rightarrow&\large degree_if_i&\large =&\large \sum_{v\in son}f_v+m\\\\
\large \Rightarrow&\large f_i&\large =&\large \frac{\large\sum_{v\in son}f_v+m}{\large degree_i}\\\\
\end{array}
\]
考虑最优策略:
向期望距离尽可能小的位置移动,不会重复经过同一个位置。
反着考虑,从期望距离最小的位置倒着走,对期望距离较大的位置更新答案(即尚未经过的位置)。因为期望距离由可能转移到的位置决定,所以记下对于一个位置可能向多少个位置转移以及转移到的位置的期望距离和。总体从\(n\)出发以堆优化dijkstra
的思路跑一遍即可,\(f_1\)就是所求答案。
窝也没有什么可以补充的。
可以稍微讲一下自己在理解时的一些问题。
Q:为什么公式是\(f_i= \frac{\sum_{v\in son}f_v+(m-degree_i)f_i}{ m}+1\)
A:可以理解成走的期望和不走的期望:
设\(sum[i]\)为\(\sum_{v\in son}f_v\)。
走的概率很明显是\(\frac{degree_i}{m}\),那么走的期望就是\(\frac{sum[i]}{m}\)。
考虑不走的话,一定是原先的期望上\(\times\)不走的概率。
不走的概率是\(\frac{m-degree_i}{m}\)
那么不走的期望就是\(\frac{m-degree_i}{m}\times f_i\)
因为无论走还是不走一定会消耗\(1\)的时间,那么需要\(+1\)。
#include <bits/stdc++.h>
#define eps (1e-10)
#define db double
#define ldb long double
#define N 300005
using namespace std;
namespace chhokmah {
struct edge { int to, nt; } E[N << 1];
int H[N], num[N];
ldb f[N], sum[N];
bool vis[N];
int ecnt, n, m;
void add_edge(int u, int v) { E[++ ecnt] = (edge) {v, H[u]}; H[u] = ecnt; }
class cmp {
public:
bool operator() (int i, int j) {
if (fabs(f[i] - f[j]) < eps) return i < j;
else return f[i] < f[j];
}
};
set <int, cmp> now;
set <int, cmp> :: iterator it;
void chhokmah() {
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i ++) scanf("%d%d", &u, &v), add_edge(u, v), add_edge(v, u);
f[n] = 0; now.insert(n);
for (int i = 1; i <= n; i ++) {
if (now.empty()) break;
it = now.begin(); int u = (*it); vis[u] = 1; now.erase(u);
for (int e = H[u]; e; e = E[e].nt) {
int v = E[e].to;
if (!vis[v]) {
now.erase(v); num[v] ++;
sum[v] += f[u];
f[v] = (sum[v] + m) / num[v];
now.insert(v);
}
}
}
printf("%0.10f\n", (db) f[1]);
}
}
int main() { chhokmah::chhokmah(); return 0; }
t3-Tree
毒瘤,做不出来。。。
贴一下标称:
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <vector>
#include <algorithm>
#define pb push_back
#define sz(a) ((int) (a).size())
using namespace std;
const int N = (int) 3e5;
vector<int> adj[N], who[N], bad[N], path, relax[N];
int n, u, v, root, ans[N], depth[N], h[N], used[N], value[N], it, tlmx[4 * N], trmx[4 * N];
void update(int t, int l, int r, int x, int y) {
if (l == r - 1)
tlmx[t] = y, trmx[t] = y + 1;
else {
int m = (l + r) / 2;
if (x < m) update(t * 2 + 1, l, m, x, y);
else update(t * 2 + 2, m, r, x, y);
tlmx[t] = max(tlmx[t * 2 + 1], (m - l) + tlmx[t * 2 + 2]);
trmx[t] = max(trmx[t * 2 + 2], trmx[t * 2 + 1] + (r - m));
}
}
int get_right(int t, int l, int r, int who, int k) {
if ((l > who) || (trmx[t] + who - r <= k)) return -1;
if (l == r - 1) return l;
int m = (l + r) / 2;
int rvalue = get_right(t * 2 + 2, m, r, who, k);
if (rvalue != -1) return rvalue;
return get_right(t * 2 + 1, l, m, who, k);
}
void get_left(int t, int l, int r, int x, int k, int &lmx, int &res) {
if (l >= x + 1) return;
if (r <= x + 1) {
if (max(tlmx[t], r - l + lmx) < k) {
lmx = max(tlmx[t], r - l + lmx);
return;
} else if (l == r - 1) {
res = l;
return;
}
}
int m = (l + r) / 2;
get_left(t * 2 + 2, m, r, x, k, lmx, res);
if (res == -1) get_left(t * 2 + 1, l, m, x, k, lmx, res);
}
void set_value(int depth, int nvalue) {
update(0, 0, h[root] + 1, depth, nvalue);
value[depth] = nvalue;
}
void update_answer(int k, int who) {
int marked = get_right(0, 0, h[root] + 1, who, k), lmx = -1, res = -1;
if (marked == -1) return;
get_left(0, 0, h[root] + 1, marked, k, lmx, res);
if (res == -1) res = 0;
if (value[res] <= k) relax[path[res]].pb(k);
else bad[path[res]][k] = max(bad[path[res]][k], lmx + 1);
}
void dfs(int v) {
path.pb(v);
int mx_u = -1, pre_mx_u = -1;
for (int i = 0; i < sz(adj[v]); ++i) {
int u = adj[v][i];
if ((mx_u == -1) || (h[mx_u] < h[u])) pre_mx_u = mx_u, mx_u = u;
else if ((pre_mx_u == -1) || (h[pre_mx_u] < h[u])) pre_mx_u = u;
}
bad[v] = vector<int>((pre_mx_u == -1) ? 1 : (1 + h[pre_mx_u]), 0);
for (int i = 0; i < sz(adj[v]); ++i) {
int u = adj[v][i];
set_value(depth[v], (u == mx_u) ? ((pre_mx_u == -1) ? 0 : (h[pre_mx_u] + 1)) : (h[mx_u] + 1));
dfs(u);
}
if (mx_u != -1) {
who[v].swap(who[mx_u]), ++it;
for (int i = 0; i < sz(adj[v]); ++i) {
int u = adj[v][i];
if (mx_u == u) continue;
used[h[u] + 1] = it;
for (int k = 0; k <= h[u]; ++k)
who[v][k] = min(who[v][k], who[u][k]);
}
for (int k = 0, mx = 0; k <= ((pre_mx_u == -1) ? -1 : h[pre_mx_u]); ++k) {
if (used[k] == it) mx = k;
set_value(depth[v], max(mx, bad[v][k]));
update_answer(k, who[v][k]);
}
}
who[v].pb(depth[v]);
set_value(depth[v], 0);
relax[v].pb(h[v]);
for (int i = 0; i < sz(relax[v]); ++i) {
int k = relax[v][i];
ans[k]++, who[v][k] = depth[v];
update_answer(k, depth[v]);
}
path.pop_back();
}
void calc_h(int v, int p = -1) {
for (int i = sz(adj[v]) - 1; i >= 0; --i) {
int u = adj[v][i];
if (u == p) {
swap(adj[v][i], adj[v].back());
adj[v].pop_back();
} else {
depth[u] = depth[v] + 1;
calc_h(u, v);
h[v] = max(h[v], h[u] + 1);
}
}
}
int main() {
scanf("%d", &n);
for (int i = 0; i + 1 < n; ++i) {
scanf("%d%d", &u, &v), --u, --v;
adj[u].pb(v), adj[v].pb(u);
}
root = 0;
calc_h(root);
for (int i = 0; i < n; i ++) cout <<
dfs(root);
for (int d = h[root] + 1; d <= n; ++d)
ans[d] = 1;
for (int k = 1, d = n; k <= n; ++k) {
while ((d > 0) && (ans[d - 1] <= k)) --d;
printf("%d%c", d, " \n"[k == n]);
}
return 0;
}
「HGOI#2019.4.19省选模拟赛」赛后总结的更多相关文章
- 5.19 省选模拟赛 小B的夏令营 概率 dp 前缀和优化dp
LINK:小B的夏令营 这道题是以前从没见过的优化dp的方法 不过也在情理之中. 注意读题 千万不要像我这个sb一样 考完连题意都不知道是啥. 一个长方形 要求从上到下联通的概率. 容易发现 K天只是 ...
- 5.19 省选模拟赛 小B的图 最小生成树 LCT
LINK:小B的图 这道题就比较容易了. 容易想到将询问离线 然后 从小到大排序 那么显然是优先放正图(x+k)的边. 考虑随着x的增大 那么负图上的边会逐渐加进来 一条边被加进来当且仅当 其权值小于 ...
- 5.19 省选模拟赛 T1 小B的棋盘 双指针 性质
LINK:小B的棋盘 考试的时候没有认真的思考 导致没做出来. 容易发现 当k>=n的时候存在无限解 其余都存在有限解 对于30分 容易想到暴力枚举 对称中心 然后 n^2判断. 对于前者 容易 ...
- 「CSP-S模拟赛」2019第四场
「CSP-S模拟赛」2019第四场 T1 「JOI 2014 Final」JOI 徽章 题目 考场思考(正解) T2 「JOI 2015 Final」分蛋糕 2 题目 考场思考(正解) T3 「CQO ...
- #10470. 「2020-10-02 提高模拟赛」流水线 (line)
题面:#10470. 「2020-10-02 提高模拟赛」流水线 (line) 题目中的那么多区间的条件让人感觉极其难以维护,而且贪心的做法感觉大多都能 hack 掉,因此考虑寻找一些性质,然后再设计 ...
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- #10471. 「2020-10-02 提高模拟赛」灌溉 (water)
题面:#10471. 「2020-10-02 提高模拟赛」灌溉 (water) 假设只有一组询问,我们可以用二分求解:二分最大距离是多少,然后找到深度最大的结点,并且把它的\(k\)倍祖先的一整子树删 ...
- 「NOIP模拟赛」数位和乘积(dp,高精)
统计方案数,要么组合数,要么递推(dp)了. 这是有模拟赛历史以来爆炸最狠的一次 T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0 T3看错题本来简单模拟又 ...
- ZROI 19.08.07模拟赛
传送门 写在前面:为了保护正睿题目版权,这里不放题面,只写题解. "正睿从来没有保证,模拟赛的题目必须原创." "文案不是我写的,有问题找喵老师去."--蔡老师 ...
随机推荐
- 从分治算法到 Hadoop MapReduce
从分治算法说起 要说 Hadoop MapReduce 就不得不说分治算法,而分治算法其实说白了,就是四个字 分而治之 .其实就是将一个复杂的问题分解成多组相同或类似的子问题,对这些子问题再分,然后再 ...
- SQL语句更新时间字段的年份、月份、天数、时、分、秒
SQL语句更新时间字段的年份.月份.天数.时.分.秒 --修改d表日期字段的年份update dset birth=STUFF(convert(nvarchar(23),birth,120),1,4, ...
- DP思想笔记
一.思想 DP也是把复杂的问题分解为许多子问题,与分治法不同的是,分治法的各个子问题互相之间没有联系,而动态规划却有.前一个子问题的结果与下一步的子问题的结果是什么有关系.这就决定了DP算法肯定有一个 ...
- JS第一部分--ECMAScript5.0标准语法 (JS基础语法)
一,调试语句 二,JS的引入方式 三,变量的使用 四,基本的数据类型 4.1,基本数据类型转换 4.2,字符串的常用方法 五,复杂数据类型 5.1,Array(数组)及常用方法 六,流程控制( 逻辑与 ...
- kubernetes 集群安装etcd集群,带证书
install etcd 准备证书 https://www.kubernetes.org.cn/3096.html 在master1需要安装CFSSL工具,这将会用来建立 TLS certificat ...
- 【题解】洛谷P3660 [USACO17FEB]Why Did the Cow Cross the Road III
题目地址 又是一道奶牛题 从左到右扫描,树状数组维护[左端点出现而右端点未出现]的数字的个数.记录每个数字第一次出现的位置. 若是第二次出现,那么删除第一次的影响. #include <cstd ...
- centos 7 Chrony 集群同步时间
Chrony有两个核心组件,分别是:chronyd:是守护进程,主要用于调整内核中运行的系统时间和时间服务器同步.它确定计算机增减时间的比率,并对此进行调整补偿.chronyc:提供一个用户界面,用于 ...
- springboot2+freemarker简单使用
一.src/main/resources/templates下新建welcome.ftl <!DOCTYPE html> <html lang="en"> ...
- 通过C#学Proto.Actor模型》之Remote
Proto.Actor中提供了基于tcp/ip的通迅来实现Remote,可以通过其Remot实现对Actor的调用. 先来看一个极简单片的远程调用. 码友看码: 引用NuGet包 Proto.Acto ...
- SpringBoot 数据篇之使用JDBC
SpringBootTutorial :: Data :: Jdbc 简介 API execute update query 实战 配置数据源 完整示例 引申和引用 简介 Spring Data 包含 ...