首页 > 其他分享 >P9755 [CSP-S 2023] 种树

P9755 [CSP-S 2023] 种树

时间:2024-03-24 11:13:44浏览次数:33  
标签:P9755 return int mid imax 100010 2023 calc CSP

P9755 [CSP-S 2023] 种树

首先,容易看出单调性,可以对最少天数二分。转为判定性问题后,我们思考如何判定。对于每棵树,都可以从刚种下长到最后一天。我们由此可以写出 \(calc(i,l,r)\) 表示第 \(i\) 棵树从第 \(l\) 天长到第 \(r\) 天的高度。

\(calc(i,l,r)=\sum\limits_{i=l}^r\max(1,b_i+i\times c_i)\)

  1. 对于 \(c_i>0\),直接把最大值去掉。

    \(calc(i,l,r)=\sum\limits_{i=l}^rb_i+i\times c_i=(r-l+1)b_i+(l+r)(r-l+1)c_i\)

  2. 对于 \(c_i<0\),\(y(x)=b_i+c_i\times x\) 一定与 \(1\) 有一个交点。当 \(x=\lfloor\frac{1-b_i}{c_i}\rfloor\) 时,此时分为三种情况:

    \(\bullet\) 当 \(x<l\) 时,\(calc(i,l,r)=r-l+1\)

    \(\bullet\) 当 \(x>r\) 时,\(calc(i,l,r)=(r-l+1)b_i+(l+r)(r-l+1)c_i\)

    \(\bullet\) 当 \(x\in[l,r]\),\(calc(i,l,r)=(x-l+1)b_i+(l+x)(x-l+1)c_i+r-x\)

至此 \(calc(i,l,r)\) 就写完了。我们该如何判定呢?对于一个固定的结束时间,我们自然能想到求出每个树最晚被种写去的时间,如果最后最优方案下有一棵树的种植时间晚于最晚种植时间,那么就不合法。

对于“求出每个树最晚被种下去的时间”,我们同样可以二分解决。如何做到最优呢?对于此时我们应该思考贪心和动态规划。先思考贪心,若我们以最晚种植时间从小到大排序,然后依次种下每棵树,是否能做到最优?答案是可以的。考虑交换相邻两棵树,这时发现,没交换时不能种下,交换后也不能种下;交换后不能种下的交换前可能可以种下。也就是当前贪心具有决策包容性,我们只关心现在最急迫的做法的是最优方案之一。

实现方面,我们可以标记沿途路径,在种一棵新的树时暴力跳到已标记的点,计算时间。这样子在种完所有树后,只遍历了每个点一次,复杂度 \(O(n)\)。

总复杂度 \(O(n\log n\log V)\)。

总结:对于具有二分性质的题目,如何判定一般用贪心或动规。对复杂一点的函数有相应的计算能力。

#include <bits/stdc++.h>
typedef long long ll;
ll read() {
	ll x = 0, f = 1;
	char c = getchar();
	while(!isdigit(c)) {
		if(c == '-') f = -1;
		c = getchar();
	}
	while(isdigit(c)) {
		x = (x << 3) + (x << 1) + (c - '0');
		c = getchar();
	} 
	return x * f;
}
ll ans;
ll n, cnt;
ll a[100010], b[100010], c[100010];
struct node {
	int to, nxt;
} e[200010];
int h[100010];
void add(int u, int v) {
	e[++cnt].to = v;
	e[cnt].nxt = h[u];
	h[u] = cnt;
}
__int128 calc(ll x, __int128 l, __int128 r) {
	if(c[x] >= 0) {
		return (r - l + 1) * b[x] + (l + r) * (r - l + 1) / 2 * c[x];
	}
	__int128 imax = (1 - b[x]) / c[x];
	if(imax < l) {
		return r - l + 1;
	}
	else if(imax > r) {
		return (r - l + 1) * b[x] + (l + r) * (r - l + 1) / 2 * c[x];
	}
	return (imax - l + 1) * b[x] + (l + imax) * (imax - l + 1) / 2 * c[x] + r - imax;
}
struct tim{
	int x;
} t[100010];
int id[100010];
bool cmp(int a, int b) {
	return t[a].x < t[b].x;
}
int st[100010], top;
int fa[100010], vis[100010];
bool check(ll x) {
	for(int i = 1; i <= n; i++) {
		if(calc(i, 1, x) < a[i]) return 0;
		int l = 1, r = n, ret = n;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(calc(i, mid, x) >= a[i]) l = mid + 1, ret = mid;
			else r = mid - 1;	
 		}	
 		vis[i] = 0;
 		id[i] = i;
 		t[i] = {ret};
	}
	std::sort(id + 1, id + n + 1, cmp);
	top = 0;
	for(int i = 1, f = 0; i <= n; i++) {
		int now = id[i];
		while(!vis[now]) st[++top] = now, vis[now] = 1, now = fa[now];
		while(top) {
			++f;
			if(t[st[top]].x < f) {
				return 0;
			}
			top--;
		} 
	}
	return 1;
}
void dfs(int u, int f) {
	for(int i = h[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if(v == f) continue;
		fa[v] = u;
		dfs(v, u);
	}
}
void Solve() {
	n = read();
	for(int i = 1; i <= n; i++) {
		a[i] = read(), b[i] = read(), c[i] = read();
	}
	for(int i = 1; i < n; i++) {
		int u = read(), v = read();
		add(u, v), add(v, u);
	}
	vis[0] = 1;
	dfs(1, 0);
	ll l = n, r = 1e9;
	while(l <= r) {
		ll mid = (l + r) >> 1;
		if(check(mid)) r = mid - 1, ans = mid;
		else l = mid + 1;
	}
	std::cout << ans << "\n";
}

int main() {
	
	Solve();

	return 0;
}

标签:P9755,return,int,mid,imax,100010,2023,calc,CSP
From: https://www.cnblogs.com/FireRaku/p/18092167

相关文章

  • [暴力题解系列] 2023年蓝桥杯-冶炼金属
    世界上存在很难的题,但不存在暴力偷不到分的题​ 这题的暴力思路比你想的更简单,我直接枚举v的数值不就行了?#include<iostream>#include<algorithm>usingnamespacestd;inta[10010],b[10010];intmain(){intn;scanf("%d",&n);for(inti=1;i<=n;i++)......
  • PAT 2023 冬 乙 方格填数
    题目描述B-4方格填数分数20全屏浏览切换布局作者 陈越单位 浙江大学2014年哈佛-麻省理工数学竞赛中一道题是这样的:将正整数1,2,...,64填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。求棋......
  • P9871 [NOIP2023] 天天爱打卡
    P9871[NOIP2023]天天爱打卡经典dp+线段树优化+离散化前两个步骤略讲,主要是离散化。首先考虑dp,朴素的,容易写出状态\(f_i\)表示考虑到第\(i\)个位置,且强制第\(i\)天跑步的最大能量值。考虑枚举最后一段跑步的时间,有\(f_i=\max(\max\limits_{k<j}f_k-(i-j)\timesd+\sum......
  • [暴力题解系列]2023年蓝桥杯-子串简写
    ​ 大伙都说暴力是最低级的算法,啊那确实。但是好的暴力才是真正牛逼的骗分。咱就是说,暴力如何骗分呢?就是基于最暴力的算法一步步优化到能得更多分的暴力。子串简写这题,首先第一步就能想到一件事情:暴力枚举子串开头和末尾的位置,检查是否是符合题目要求的字符,如果是,并且长度大于......
  • 2023年红蓝对抗-HW蓝队基本知识点
    1.Linux排查思路(1)首先检测用户账号安全,如新增用户和可疑用户以及高权限用户。(2)history命令查看历史linux指令,uptime查看用户登录信息(3)检查端口(netstat命令)和进程(ps命令),重点观察资源占用率高的进程(4)检查日志信息,var/log文件夹内的一些系统日志和安全日志。(5)利用自动......
  • 机器学习金融预测领域2023部分综述论文阅读记录
    23年的综述最近读了3篇,总结笔记如下:本期所有论文链接:2023综述https://www.alipan.com/s/ySur3StxKip点击链接保存,或者复制本段内容,打开「阿里云盘」APP,无需下载极速在线查看,视频原画倍速播放。(2023)A_Systematic_Survey_of_AI_Models_in_Financial_Mark评价:原文写的一般,可以......
  • SpringBoot 面向面试学习(2023.03.23更新)
    导语在网上找了很多SpringBoot相关的教程,要么是针对初学者面向实战入门的视频,要么基于面试但存在收费或不全面的问题……因此参考网上博客特此总结了一些可能常见的面试题,循序渐进,以问题为导向,以面试为场景进行学习/复习。JavaGuide提供的Spring常见面试题总结可以去看,里面......
  • #17 2023.3.18
    645.loj4038「SNOI2024」树V图646.loj4039「SNOI2024」矩阵647.loj4040「SNOI2024」拉丁方648.loj4041「SNOI2024」平方数649.loj4042「SNOI2024」公交线路650.loj3903「PA2022」Palindrom651.loj3904「PA2022」WielkiZderzaczTermionów652.loj......
  • BUPT 2024 Spring Training #3(ICPC2023 杭州站)Ag复盘
    D-OperatorPrecedence求一个长度为\(2n\)的序列\(a_{2n}\)满足条件\((a_1×a_2)+(a_3×a_4)+\ldots+(a_{2n-1}×a_{2n})=a_1×(a_2+a_3)×\ldots×(a_{2n-2}+a_{2n-1})×a_{2n}\)solution构造题显然找特殊规律。考虑到乘法构造难度大于加法,可以从乘法开始考虑。......
  • 机试重点题-2021/2023
    20215:由二叉树前々序列和中々序列得到后々序列列 #include<iostream>#include<unordered_map>usingnamespacestd;constintN=50010;intn;inta[N],b[N];//前序,中序unordered_map<int,int>p;voidbuild(intal,intar,intbl,intbr){if(al......