首页 > 其他分享 >SS241030B. 世界(world)

SS241030B. 世界(world)

时间:2024-10-30 15:42:04浏览次数:1  
标签:SS241030B cnt le int sum 世界 ch world ll

SS241030B. 世界(world)

题意

在一个 \(n\) 列的竖着的二维世界里。每列有一个高度为 \(a_i\) 的石柱。你从 \((1,a_1)\) 的石头上面出发。每次可以往左或右边走一步(前提是左边或右边没有石头)、或者挖掉左边或者右边的石头、或者挖掉自己脚底下的石头。

挖掉一个石头会使得它上面的所有石头一起消失。

你有 \(k\) 的血量,如果脚下没有踩着石头,你就会掉下去,掉下 \(h\) 个单位会受到 \(h^2\) 的伤害(注意挖自己脚下也会掉下去)。

问最少操作多少次,使得血量非负,对于每个 \(1\le i \le n\),到达 \((i,0)\) 上面。

solution

想 + 写 + 调花了 3h+,先冲完 t2 正解再写 t3、t4 暴力,这是赌博。赌博是有很大风险的。不能再赌了,虽然赢了的结果极具诱惑性,如 CSP-S2023,但是如果输了就会像 GDOI2024 一般惨烈。建议下次先写后面的暴力。

赛事做法太恶心了,现在整理一下。

省流:设 \(f_i\) 表示不走回头路走到 \((i,0)\) 的最小次数,\(ans_i=\min(f_i,f_{j,j>i}+2(j-i))\)。设 \(g_j=f_j+2j\),变成求 \(ans_i=\min_{j\ge i}\{g_j\}-2i\)。求 \(f_i\) 使用简单贪心 + 二分 + 想象出式子。时间复杂度 \(O(n \log k)\)。

显然你不会往上走只会往下掉。

可以感觉到要走到 \((i,0)\),你会尽量在石柱的顶部走,可能你走到第 \(i\) 列就一直往下挖,也可能走到第 \(i\) 列之后你继续往右边走(因为可以多掉几次,减少挖石头的代价),然后再掉头回来,此时你左侧的石柱全部比你高(否则你之前就会掉到石柱的高度),因此你需要挖一次走一次。

把每个前缀最小值的列称为关键列。对与非关键列你一定要先挖才能走过去,而对于关键列,你一定会先往下挖几格然后直接跳下去,你挖的石头数量不会超过两个柱子的高度差。

对于不走回头路的一类,你的方案一定是往下挖和跳关键列,往右挖和走非关键列。走到 \(\le i\) 的最靠后的关键列时一直下挖到低,然后边挖边走到 \((i,0)\)。

赛后才发现一定会走到最右边的关键列才下挖,一定不劣。

对于走回头路的一类,我们枚举关键列 \(j\),先走到 \(j\) 的顶部然后往下挖到底,然后左挖一下,左走一下,走到 \((i,0)\)。

可以证明这样是最优的。

于是对于每个关键列 \(i\),可以设 \(f_i\) 表示走到 \((i,0)\) 的最小次数。

第一种情况就直接是最右边的关键列 \(f_j\) 加上 \(2(i-j)\)。

第二种情况就枚举 \(j\ge i\),算 \(f_j+2(j-i)\)。

发现 \(f_j-2(j-i)=f_j-2j+2i\),于是直接把 \(2j\) 揉进 \(f_j\) 里面,变成求 \((\min_{j\ge i} f_j)+2i\)。求个后缀最小值即可。

然后现在解决如何求 \(f_i\)。

首先我们希望尽可能地多跳少挖,但是又要保证不会摔死。比较显然的是我们希望每次跳的高度尽量相等。设这个高度是 \(x\),算一下伤害是多大,然后 \(O(1)\) 或者二分求解。有:

\[伤害=cnt_{d>x}\cdot x^2+(\sum d [d>x] -cnt_{d>x}\cdot x)+\sum d^2 [d \le x]+a_i \]

就是高度差 \(>x\) 的地方跳 \(x\) 行,\(\le x\) 的地方跳 \(d\),然后加上 \(>x\) 的地方往下挖的伤害和在 \(a_i\) 处往下挖的伤害。

表示为 \(cnt\cdot x^2 +sum-sum'+s+a_i\) 应该可以对应上吧

发现 \(cnt\)、\(sum\) 都是与 \(x\) 相关的分段函数,因此只能二分做。显然二分上界是 \(\sqrt{k}\),下界需要取到 \(1\),否则下文算 \(y\) 会出现除数为 \(0\) 的情况。

你发现 \(x\) 其实是单调不增的,所以上界可以双指针优化常数。

这里注意 \(d=0\) 的情况需要特判,此时你会直接往右边走一步,因此 \(f_i=f_{i-1}+1\)。然后又引出非关键列的 \(f_i\) 是多少,因为你会往右边挖一次然后走一步,因此有 \(f_i=f_{i-1}+2\)。

但是可能有一部分 \(>x\) 的地方可以选择跳 \(x+1\),设有 \(y\) 个地方要跳 \(x+1\)。(下面的式子就要求上面的式子必须是 \(>x\) 和 \(\le x\),不能是 \(\ge x\) 和 \(< x\),否则 \(cnt\) 个位置有一些可能不能跳 \(x+1\) 的)

\[y(x+1)^2+(cnt-y)x^2+sum-sum'-y+s+a_i \le k \]

这个不等式可以 \(O(1)\) 算。即

\[y=\lfloor \frac{k-cnt-x^2-sum+sum'-s-a_i}{(x+1)^2-x^2-1}\rfloor \]

然后就是:

\[f_i=i-1+sum-sum'-y+a_i+cnt' \]

这里是,往右边走花费 \(i-1\) 次,往下挖花费 \(sum-sum'-y\) 次和 \(a_i\) 次。\(cnt'\) 是 \(1\sim i\) 之间非关键列的个数,因为每个非关键列需要往右挖。

这些 \(cnt\)、\(sum\)、\(s\) 可以树状数组维护。

然后算《省流》的美丽式子就做完了。时间复杂度 \(O(n \log k)\)。感觉细节挺多的?主要是式子比较难想象出来。

code

简单重构了一下赛场恶心代码。现在简洁了一些。

#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
#define gc getchar_unlocked
#define isdigit(x) (x>='0'&&x<='9')
template <typename T>
void read(T &x) {
	x=0;
	T fl=1;
	char ch=gc();
	for(;!isdigit(ch);ch=gc()) if(ch=='-') fl=-1;
	for(;isdigit(ch);ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
	x=x*fl;
}
#define pc putchar_unlocked
template <typename T>
void write (T x,char ch) {
	static int st[40];
	int top=0;
	if(x<0) pc('-'),x=-x;
	ll y=10;
	do {
		st[top++]=x%10;
		x=x/y;
	}while(x);
	while(top) pc(st[--top]+'0');
	pc(ch);
}
constexpr int N=1e6+7;
constexpr ll inf=2e18+7;
int n,a[N],c[N];
ll k;
ll f[N];
ll l,r;
ll cnt0;
struct tree {
	ll tr1[N][2],tr2[N];
	ll b[N];
	int m;
	void init() {
		rep(i,1,n) b[i]=c[i];
		sort(b,b+n+1);
		m=unique(b,b+n+1)-b-1;
	}
	void add1(int x,ll cnt,ll sum) {
		for(;x<=m;x+=x&-x) tr1[x][0]+=cnt,tr1[x][1]+=sum;
	}
	void add2(int x,ll s) {
		for(;x<=m;x+=x&-x) {
			tr2[x]+=s;
			if(tr2[x]>k) tr2[x]=k+1;
		}
	}
	void ask1(int x,ll &cnt,ll &sum) {
		for(;x;x-=x&-x) cnt+=tr1[x][0],sum+=tr1[x][1];
	}
	void ask2(int x,ll &s) {
		for(;x;x-=x&-x) {
			s+=tr2[x]; 
			if(s>k+1) { s=k+1; return; }
		}
	}
	void query(ll x,ll &cnt,ll &sum,ll &s) {
		int y=upper_bound(b+1,b+m+1,x)-b;
		ask1(m-y+1,cnt,sum);
		ask2(y-1,s);
	}
	void insert(ll x) {
		ll y=lower_bound(b+1,b+m+1,x)-b;
		add1(m-y+1,1,x);
		add2(y,x*x);
	}
}T;
ll check(ll x,int a) {
	ll cnt=0,sum=0,s=0;
	T.query(x,cnt,sum,s);
	__int128 ss=(__int128)cnt*x*x+sum-cnt*x+s+a;
	return ss>k?k+1:ss;
}
ll find1(int i,ll l,ll r) {
	while(l<r) {
		ll mid=(l+r+1)>>1;
		if(check(mid,a[i])>k) r=mid-1;
		else l=mid;
	}
	return l;
}
ll find2(ll i,ll x,ll &sum,ll &cnt) {
	ll s=0;
	T.query(x,cnt,sum,s);
	if(cnt==0) return 0;
	return (k-cnt*x*x-sum+cnt*x-s-a[i])/((x+1)*(x+1)-x*x-1);
}
int la;
bool fl[N];
ll g[N];
int main() {
	#ifdef LOCAL
	freopen("my.out","w",stdout);
	#else 
	freopen("world.in","r",stdin);
	freopen("world.out","w",stdout);
	#endif
	read(n),read(k);
	l=1,r=sqrt(1.0*k);
	rep(i,1,n) read(a[i]);
	la=a[1];
	rep(i,1,n) {
		if(a[i]<=la) {
			c[i]=la-a[i];
			la=a[i];
		}else fl[i]=1;
	}
	T.init();
	f[1]=a[1];g[1]=a[1]+2;
	rep(i,2,n) {
		if(fl[i]) { f[i]=f[i-1]+2; g[i]=f[i]+2*i; cnt0++; continue;}
		if(c[i]==0) {
			f[i]=f[i-1]+1;
			g[i]=f[i]+2*i;
			continue;
		}
		T.insert(c[i]);
		ll x=find1(i,l,r);
		r=x;
		ll sum=0,cnt=0;
		ll y=find2(i,x,sum,cnt);
		f[i]=i-1+sum-cnt*x-y+a[i]+cnt0;
		g[i]=f[i]+2*i;
	}
	per(i,n-1,1) {
		g[i]=min(g[i],g[i+1]);
	}
	rep(i,1,n) {
		ll ans=g[i]-2*i;
		write(ans,' ');
	}
}

标签:SS241030B,cnt,le,int,sum,世界,ch,world,ll
From: https://www.cnblogs.com/liyixin0514/p/18515969

相关文章

  • 关于我、重生到500年前凭借C语言改变世界科技vlog.12——深入理解指针(2)
    文章目录1.数组名与地址1.1arr1.2sizeof(arr)1.3&arr2.指针访问数组3.一维数组传参本质4.指针数组5.二级指针希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力!1.数组名与地址有这么一个数组,数组名为arrintarr[10]={1,2,3,4,5,6,7,8,9}int......
  • d3dx9_43.dll缺失导致小小世界Smalland无法启动?小小世界Smalland玩家必看d3dx9_43.dll
    当d3dx9_43.dll文件缺失导致小小世界Smalland无法启动时,作为玩家,你可以采取以下紧急应对措施来解决这一问题:一、了解d3dx9_43.dll文件的重要性d3dx9_43.dll是DirectX9.0c的一个重要组件,它负责为基于DirectX技术的游戏和应用程序提供图形和声音效果的支持。如果该文件缺失或......
  • Springboot世界美食风情展示系统211wo(程序+源码+数据库+调试部署+开发环境)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表用户,美食类别,世界美食,美食攻略,美食订单开题报告内容一、项目背景与意义随着经济的快速发展和网络技术的进步,互联网已经深刻改变了人们的生活方式。电子商务......
  • 【数据结构与算法】《Java 算法宝典:探秘从排序到回溯的奇妙世界》
    目录标题:《Java算法宝典:探秘从排序到回溯的奇妙世界》一、排序算法1、冒泡排序2、选择排序3、插入排序4、快速排序5、归并排序二、查找算法1、线性查找2、二分查找三、递归算法四、动态规划五、图算法1.深度优先搜索(DFS)2.广度优先搜索(BFS)六、贪心算法七、分治算法......
  • 程序员世界大冒险d45Ⅲ
    Java实现数据库的增删改:第一步:连接配置数据库如下packagecom.itheima.jdbc;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.Statement;/*JDBC快速入门*/publicclassJDBCdemo{publicstaticvoidmain(String[]args)throwsException......
  • 程序员世界大冒险d45Ⅱ
    设置外键约束如下:--创建表emp员工表createtableemp(idintprimarykey,namevarchar(50)notnullunique,ageint,dep_idint);select*fromemp;--创建表dept部门表createtabledept(idintprimarykey,dep_namevarchar(50)unique,addressvarchar(50))......
  • Python 潮流周刊#74:创下吉尼斯世界记录的 Python 编程课(摘要)
    本周刊由Python猫出品,精心筛选国内外的250+信息源,为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景:帮助所有读者精进Python技术,并增长职业和副业的收入。本期分享了12篇文章,12个开源项目,2则音视频,全文2300字。好消息:即日起至......
  • 程序员世界大冒险d45
    读书笔记一:编程的心态与职业发展在《程序员修炼之道:从小工到专家》一书的开篇,作者强调了编程的心态对于职业发展的重要性。初入职场的程序员,往往被各种技术和任务所淹没,急于完成工作,缺乏长远思考。作者提出,务必要培养一种积极向上的学习和成长心态,将编程视为一种修炼,而不是单纯的......
  • 《虚拟现实的边界:探索虚拟世界的未来可能》
    内容概要在虚拟现实(VR)技术的浪潮中,我们见证了其从实验室的奇想逐渐走向日常生活的非凡旅程。技术发展的背后是不断突破的创新,早期的设备虽然笨重,但如今却趋向精致、轻巧,用户体验显著提升。想象一下,在未来的课堂上,学生们不再是书本里的观察者,而是亲身参与在古代文明的盛宴中,或......
  • C# Hello,World(1)
    1.创建工程2.书写代码Console.WriteLine("Hello,World!");3.运行代码......