CSP-S 模拟赛 32

news/2024/10/6 4:13:40/文章来源:https://www.cnblogs.com/laoshan-plus/p/18447342

CSP-S 模拟赛 32

rnk25,\(0+0+9+0=9\)

T1 [CF1578K] Kingdom of Islands

还没改出来。

T2 [CF1578L] Labyrinth

警钟嚼烂:改代码改干净。

首先考虑如果从 \(a\) 走到 \(b\),人最胖是多少。毫无疑问,这是一个最大生成树问题。在这个基础上考虑原问题,我们发现由于人会越来越胖,一定有边就逐渐断掉了,且最先断掉的边一定是最窄的边。

那么我们需要在这条边断掉以前吃掉这条边连接的两棵子树的任意一边的所有糖果,否则就再也过不去了,也就没有办法吃掉所有糖果。

然后我们易证:最先吃掉这条边的一颗子树上的所有糖果一定不劣于其他选择。

设这条边连接的子树为 \(u,v\),这两棵子树的糖果和分别为 \(s_u,s_v\)

考虑如果先吃树 \(v\) 的一些糖,然后再过去吃掉树 \(u\) 的所有糖,且还能从 \((u,v)\) 这条边返回,则证明这个过程中人的宽度一定不超过 \(w(u,v)\)。那么如果先吃树 \(u\) 的所有糖之后再吃树 \(v\),总宽度一定也是不超过 \(w(u,v)\) 的。所以不会劣。

我们发现:如果原问题在树 \(v\) 上的答案为 \(f_v\),则新加入边 \((u,v)\) 后,答案就是 \(\min\big(f_v-s_u,w(u,v)-s_u\big)\)。如果是先吃完树 \(v\),答案也是同理。所以当前总的答案就是

\[\max\Big(\min\big(f_v-s_u,w(u,v)-s_u\big),\min\big(f_u-s_v,w(u,v)-s_v\big)\Big)~. \]

在 Kruskal 求最大生成树的过程中,用并查集可以很方便的维护这些信息。

最后一点,如何在最后输出答案时找到那一条宽度最小的边?因为 Kruskal 最大生成树是按边权从大到小加的,所以最后加的那条边就是宽度最小的边。

#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
#define int long long
using namespace std;char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){int x=0;char ch=getchar();while(!isdigit(ch))ch=getchar();while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x;
}
template<typename T>
void write(T x,char sf='\n'){if(x<0)putchar('-'),x=~x+1;int top=0;do str[top++]=x%10,x/=10;while(x);while(top)putchar(str[--top]+48);putchar(sf);
}
constexpr int MAXN=2e5+5;
mt19937 wdz(chrono::steady_clock::now().time_since_epoch().count());
int n,m,c[MAXN];
struct Edge{int u,v;long long w;bool operator<(const Edge&x)const{return w>x.w;}
}e[MAXN];
int f[MAXN];
int find(int x){if(f[x]^x)f[x]=find(f[x]);return f[x];
}
long long dp[MAXN],sum[MAXN],rt;signed main(){freopen("fat.in","r",stdin);freopen("fat.out","w",stdout);n=read(),m=read();for(int i=1;i<=n;++i)sum[i]=c[i]=read();for(int i=1;i<=m;++i)e[i]={read(),read(),read()};sort(e+1,e+m+1);iota(f+1,f+n+m+1,1);memset(dp,0x3f,sizeof(int)*(n+5));for(int i=1,u,v,fu,fv;i<=m;++i){u=e[i].u,v=e[i].v;fu=find(u),fv=find(v);if(fu==fv)continue;f[fu]=f[fv]=i+n;rt=i+n;dp[i+n]=max(min(e[i].w-sum[fu],dp[fv]-sum[fu]),min(e[i].w-sum[fv],dp[fu]-sum[fv]));sum[i+n]=sum[fu]+sum[fv];}write(dp[rt]<=0?-1:dp[rt]);return fw,0;
}

T3 [CF1578J] Just Kingdom

警钟搅烂:浮点数注意精度保留 eps。

初看这给来给去的很麻烦,事实上,我们发现:如果当前节点 \(u\) 需要 \(x\) 块钱,则他父亲需要的钱为 \(x+\sum_{v\in\text{bro}}\min(\mathit{siz}_v,x)\) 块钱。可以理解为一个香槟塔的东西(wzw 说的)。

这题的关键在于,题目要求每个节点的答案,这导致对于每个节点,每个父亲要求的这个儿子都不一样。如果我们对每个节点都暴力向上跳父亲,然后按照刚刚推出来的这个东西跑 DFS,这就是一个 \(O(n^2)\) 的做法,可以拿到 63pts 的好成绩。

下面是题解的话。

那我们看怎么快速地维护这个东西,想到倍增。我们发现如果 \(x\le\mathit{siz}_v\),那么它父亲得到的 \(x\) 至少翻倍,令这个点为 “倍增点”。注意到在一个树中的任意一点 \(u\) 跳到根节点中至多有 \(\log\sum m\) 个倍增点,而在跳到倍增点之前的路径,其对 \(x\) 的增量是容易预处理的。

于是考虑一个倍增,\(f_{u,i}\) 代表从 \(u\) 到第 \(2^i\) 级父亲,要求 \(x\le\;?\) 才不会遇到倍增点。统计答案的时候就是倍增跳倍增点,在倍增点上的答案计算可以通过提前给该点儿子点权和排序然后二分来快速求得。复杂度 \(O(n\log n(\log n+\log m))\)

#include<bits/stdc++.h>
#define fw fwrite(obuf,p3-obuf,1,stdout)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) (p3-obuf<1<<20?(*p3++=(x)):(fw,p3=obuf,*p3++=(x)))
using namespace std;char buf[1<<20],obuf[1<<20],*p1=buf,*p2=buf,*p3=obuf,str[20<<2];
int read(){int x=0;char ch=getchar();while(!isdigit(ch))ch=getchar();while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x;
}
template<typename T>
void write(T x,char sf='\n'){if(x<0)putchar('-'),x=~x+1;int top=0;do str[top++]=x%10,x/=10;while(x);while(top)putchar(str[--top]+48);putchar(sf);
}
constexpr int MAXN=3e5+5;
int n,F;
int head[MAXN],tot;
struct{int v,nxt;}e[MAXN];
void addedge(int u,int v){e[++tot]={v,head[u]};head[u]=tot;
}
int fa[MAXN][31];
long long val[MAXN];
void dfs(int u){for(int i=head[u];i;i=e[i].nxt){dfs(e[i].v);val[u]+=val[e[i].v];}
}
int son[MAXN];
long long dp[MAXN];
long long su[MAXN][31],f[MAXN][31];
vector<long long>s[MAXN],va[MAXN];
void dfs2(int u,int x){if(u==x)return;dfs2(son[u],x);dp[u]+=dp[son[u]];for(int i=head[u];i;i=e[i].nxt){if(e[i].v==son[u])continue;dp[u]+=min(val[e[i].v],dp[son[u]]);}
}
void dfs3(int u){for(int i=1;i<=F;++i)fa[u][i]=fa[fa[u][i-1]][i-1];if(u^1){f[u][0]=va[fa[u][0]].size()==1?0:va[fa[u][0]][va[fa[u][0]].size()-1-(va[fa[u][0]][va[fa[u][0]].size()-1]==val[u])];su[u][0]=s[fa[u][0]][s[fa[u][0]].size()-1]-val[u];for(int i=1;i<=F;++i){su[u][i]=su[u][i-1]+su[fa[u][i-1]][i-1];f[u][i]=max(f[u][i-1],f[fa[u][i-1]][i-1]-su[u][i-1]);}}for(int i=head[u];i;i=e[i].nxt)dfs3(e[i].v);
}int main(){freopen("share.in","r",stdin);freopen("share.out","w",stdout);n=read()+1;F=log2(n);for(int i=2,f;i<=n;++i){f=read(),val[i]=read();addedge(f+1,i);fa[i][0]=f+1;}dfs(1);for(int i=2;i<=n;++i){va[fa[i][0]].emplace_back(val[i]);s[fa[i][0]].emplace_back(0);}for(int i=1;i<=n;++i){if(va[i].empty())continue;sort(va[i].begin(),va[i].end());s[i][0]=va[i][0];if(va[i].size()==1)continue;for(int j=1;j<(int)va[i].size();++j)s[i][j]=s[i][j-1]+va[i][j];}dfs3(1);for(int i=2;i<=n;++i){int x=i;long long t=val[i];while(x){for(int j=F;~j;--j){if(x&&t>=f[x][j]){t+=su[x][j];x=fa[x][j];}}if(!x)continue;int p=upper_bound(va[fa[x][0]].begin(),va[fa[x][0]].end(),t)-va[fa[x][0]].begin()-1;long long lst=t;if(p<0){t+=lst*s[fa[x][0]].size();t-=min(val[x],lst);}else{t+=lst*(s[fa[x][0]].size()-p-1);t+=s[fa[x][0]][p];t-=min(val[x],lst);}x=fa[x][0];}write(t);}return fw,0;
}

T4 [CF1578B] Building Forest Trails

好玩的:既然 \(n\) 个点平均分布在一个圆上,三角函数计算每个点的坐标,每修一条路就连一条直线计算解析式,和之前连的直线联立计算交点判断是否在圆内,然后统计答案。这是一个标准的 \(O(n^2)\),期望得分 20pts,实际得分 26pts(初中)或 27pts(高中)。

正解唐了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/808088.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10.Java集合框架_List接口

集合与数组的区别数组:长度开始时必须指定,而且一旦指定,不能修改。 保存的必须为同一类型的元素。 使用数组进行增加/删除元素比较麻烦。集合:可以动态保存任意多个对象,使用比较方便。 提供了一系列方便操作对象的方法: add、remove、set、get。 使用集合添加,删除新元…

20240924

[牛半仙的妹子 Tree(tree)](http://ac.robo-maker.cn/d/contest/p/ZY1044?tid=66f28cd11bca2159e88c8fb0) 我们会发现其实牛半仙发癫时就等于将以前的标记清空,从头开始,所以我们可以考虑根号分治,如果两个牛半仙发癫的时间间隔小于 \(\sqrt n\) ,那么我们可以直接暴力枚举两…

『模拟赛』冲刺CSP联训模拟2

『模拟赛记录』冲刺CSP联训模拟2Rank 不重要了A. 挤压 你说的对,期望怎么能算签呢? 一个重要的性质:一个数的平方可以在二进制下表示为 \(\sum_{i,j}\ s_i\ s_j\ 2^{i+j}\),所以就可以分别求每一位对答案的贡献了。 设 \(f_{i,1/0,1/0}\) 表示到第 \(i\) 个数我们枚举的两位…

PbootCms上传图片变模糊、上传图片尺寸受限的解决方案

在使用PbootCMS的过程中,如果上传的图片被压缩变得模糊,通常是因为上传的图片尺寸过大。PbootCMS 默认的上传图片限制宽度为 1920 像素,缩略图的限制大小为 10001000 像素。可以通过调整这些参数来解决这个问题。 解决方案打开 config.php 文件 调整 max_width 和 max_heigh…

ROS基础入门——实操教程

ROS新人可看ROS基础入门——实操教程前言 本教程实操为主,少说书。可供参考的文档中详细的记录了ROS的实操和理论,只是过于详细繁杂了,看得脑壳疼,于是做了这个笔记。Ruby Rose,放在这里相当合理前言:本文初编辑于2024年10月24日 CSDN主页:https://blog.csdn.net/rvdgds…

PbootCMS增加可允许上传文件类型,例如webp、mov等文件格式扩展

在PbootCMS中增加可允许上传的文件类型(例如 webp、mov 等文件格式),需要在多个地方进行配置。以下是详细的步骤: 操作步骤 1. 修改 config.php 文件 首先需要修改 config.php 文件,增加允许上传的文件类型。打开 config.php 文件打开 config.php 文件,通常位于 /config …

出现“登录失败,表单提交校验失败”,请检查服务器环境

如果出现“登录失败,表单提交校验失败”,请检查服务器环境,然后刷新页面重试,或者删除 runtime 文件夹,然后刷新页面重试。 操作步骤删除 runtime 文件夹使用 FTP 客户端或 SSH 连接到服务器。 删除 runtime 文件夹:bashcd /path/to/your/site rm -rf runtime刷新页面清除…

多次密码错误导致登录界面锁定,可以删除网站的 runtime 文件夹

如果多次密码错误导致登录界面锁定,可以删除网站的 runtime 文件夹,然后刷新页面重试。 操作步骤删除 runtime 文件夹使用 FTP 客户端或 SSH 连接到服务器。 删除 runtime 文件夹:bashcd /path/to/your/site rm -rf runtime刷新页面清除浏览器缓存。 重新访问后台登录页面扫…

红日靶机(三)笔记

VulnStack-红日靶机三 概述 相交于前边两个靶场环境,靶场三的难度还是稍难一点,有很多兔子洞,这就考验我们对已有信息的取舍和试错,以及对渗透测试优先级的判断。涉及到对数据库操作的试错,对 joomla 框架 cve 的快速学习,php 中 用到disabled_function 的 bypass ,对li…

快乐数学2勾股定理0000000

2 勾股定理 在任意一个直角三角形中,两条直角边的平方和等于斜边的平方。 a + b = ca 和 b 分别表示直角三角形的两条直角边长度。 c 表示斜边长度。我们大多数人都认为这个公式只适用于三角形和几何图形。勾股定理可用于任何形状,也可用于任何将数字平方的公式。 2.1 了解面…

信息学奥赛复赛复习11-CSP-J2020-04方格取数-动态规划、斐波那契数列、最优子结构、重叠子问题、无后效性

PDF文档公众号回复关键字:202410041 P7074 [CSP-J2020] 方格取数 [题目描述] 设有 nm 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的…

python相平面 图形

二阶非线性自治系统绘制相平面图。假设我们有一个简单的阻尼摆系统,其状态方程可以表示为: \[ dx1/dt = x2 \\dx2/dt = -cx2 - gsin(x1) \] import numpy as np import matplotlib.pyplot as plt from scipy.integrate import odeint # 定义系统的状态方程 def pendu…