首页 > 其他分享 >NOIP2023模拟8联测29 C. 蛋糕

NOIP2023模拟8联测29 C. 蛋糕

时间:2023-11-01 20:33:49浏览次数:33  
标签:return LL 29 联测 蛋糕 NOIP2023 mxd 矩形 mnd

NOIP2023模拟8联测29 C. 蛋糕

目录

题目大意

你现在得到了一个二维蛋糕,它从左到右可以分成 \(n\) 列,每列高为 \(a_i\) 。对于每一列,又可以从下到上分为 \(a_i\) 块,并且最上面一块权值为 \(1\) ,从上到下权值依次加 。每一列的最上面的权值为 的块的上表面有“奶油”。

你现在要把这一个蛋糕分成若干个矩形,要求每一个矩形上都要有“奶油”,也即每个矩形要包含至少一个权值为 \(1\) 的块。显然蛋糕中的每一格都必须被划分到恰好一个矩形内,且矩形不能包含没有蛋糕的格子。

定义每一块矩形的代价为其每一行的最大值之和,即 \(\sum_{i = l}^r(\max_{j -= d}^u v_{i , j})\) 。特别地,对于宽(列数)为 \(1\) 的矩形,代价为矩形内权值的最大值。请你最小化划分整个蛋糕的代价。

\(n\le 3000\)

思路

考虑维护区间最大值和最小值的位置。

然后搞一个 \(dp_{l , r , k}\) 表示区间 \([l , r]\) 内从下往上前 \(k\) 层的最小代价。

通过一通推理发现,对于一个区间 \([l , r]\) 的最优策略就是删除最高的那一列或者把区间的所有蛋糕删到最矮的那一列那么高。

搞一个记忆化就好了

code

#include <bits/stdc++.h>
#define LL long long
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
using namespace std;
const int N = 3005;
int n , min1[N][N] , max1[N][N];
LL a[N];
map<LL , LL> dp;
LL gt (LL l , LL r , LL k) { return (l * (N + 1) + r) * N + k; }
LL getsum (LL x , LL y) { return (x + y) * (y - x + 1) / 2; }
LL solve (int l , int r , LL k) {
	LL id = gt (l , r , k);
	if (dp.count (id)) return dp[id];
	int mxd = max1[l][r] , mnd = min1[l][r];
	LL ans = a[mxd] - k;
	if (mxd > l) ans += solve (l , mxd - 1 , k);
	if (mxd < r) ans += solve (mxd + 1 , r , k);
	if (l != r) {
		LL ans1 = getsum (a[mxd] - a[mnd] + 1 , a[mxd] - k);
		if (l < mnd) ans1 += solve (l , mnd - 1 , a[mnd]);
		if (mnd < r) ans1 += solve (mnd + 1 , r , a[mnd]);
		ans = min (ans , ans1);
	}
	return dp[id] = ans;
}
int main () {
	freopen ("cake.in" , "r" , stdin);
	freopen ("cake.out" , "w" , stdout);
	scanf ("%d" , &n); 
	fu (i , 1 , n) {
		scanf ("%lld" , &a[i]);
	}
	fu (l , 1 , n) {
		min1[l][l] = max1[l][l] = l;
		fu (r , l + 1 , n) {
			min1[l][r] = min1[l][r - 1] , max1[l][r] = max1[l][r - 1];
			if (a[min1[l][r - 1]] > a[r]) min1[l][r] = r;
			if (a[max1[l][r - 1]] < a[r]) max1[l][r] = r;
		}
	}
//	return 0;
	printf ("%lld" , solve (1 , n , 0));
	return 0;
}

标签:return,LL,29,联测,蛋糕,NOIP2023,mxd,矩形,mnd
From: https://www.cnblogs.com/2020fengziyang/p/17804035.html

相关文章

  • tdc++.so.6: version `GLIBCXX_3.4.29' not found
     001、python程序报错如下: 002、问题分析a、调用的是python程序b、libstdc++.so.6是c++标准库执行python程序时,需要调用c++标准库,libstdc++.so.6(lib=glib,6表示第6版),版本不匹配报错,无法找到:GLIBCXX_3.4.29。 003、确认调用的哪里的python程序(base)[b20223040......
  • 2023NOIP A层联测20 点餐
    2023NOIPA层联测20点餐题目很好,可惜考试没想到。思路可以按照\(b\)从小到大排序,固定选择个数\(k\),枚举选择的盘子\(x\)的\(b\)最大,最优解肯定是贪心的在前\(x-1\)个盘子里选择\(k-1\)个最小的,使用权值主席树可以在\(O(\log_2n)\)的时间内求解。我们令\(f(k)\)......
  • codeforces 1829G. Hits Different 容斥原理+记忆化搜索
    题目描述:给定一个n,把n给打倒,然后递归的求出包含n在内的上面所有的会倒下的瓶子值的平方和。这里使用二分先求出目前给定的n的行号i和列号j。观察可以发现,对于所有的列号j,j=1或者j=i时,是需要考虑往上单边的总和,其他情况都有两个分支。再观察可以发现,两个分支在再上一行的重合部......
  • 实验三 计算机九班周天意202383290419
    一、实验目的1.能正确使用c语法规则定义、声明、调用函数2.能正确编写递归函数3.针对具体问题场景,能合理抽象出独立的功能模块,正确定义函数并使用,使得代码更具可读性、可维护性4.针对具体问题场景,能正确、合理使用全局变量和局部static变量,解决实际问题二、实验准备实验前......
  • 29win32编程基础——线程控制
    suspendThred挂起线程ResumeThread恢复线程结束线程1、ExitThread2、线程函数返回,即线程正常结束,正常结束3、线程强制结束TerminateThread,告诉操作系统要结束线程WaitForSingleObject TerminateThread和ExitThread区别是:1、TerminateThread是异步调用,用于强制终止线程;E......
  • 【算法题】2909. 元素和最小的山形三元组 II
    题目:给你一个下标从0开始的整数数组nums。如果下标三元组(i,j,k)满足下述全部条件,则认为它是一个山形三元组:i<j<knums[i]<nums[j]且nums[k]<nums[j]请你找出nums中元素和最小的山形三元组,并返回其元素和。如果不存在满足条件的三元组,返回-1。示例1:......
  • 23/10/29 模拟赛总结
    时间安排7:35-8:20直接开T1,发现不会做。8:20-8:40把T2T3T4都看了,T2和T1一样是我必不可能会的人类智慧题,T3看上去就很劝退,T4是我喜欢的树上问题,直接倒序开题。8:40-10:20想了T4,得到了一个\(O(n^2)\)的暴力,高达40分,直接开写。写完之后过不了第二个样例,发现假......
  • 10.23~10.29
    补题补了Mea的Math2反演内容。学习了一下树分块的模板。补了部分Hanghang的dp优化。补了一点基础DS、基础dp。比赛打了一场lxsround和北大附联考,感觉发挥不错(希望NOIP有这个状态),但是都有挂分。lxsround第四题写挂了,100->40。北大附联考第三题写挂了,100->......
  • 上周热点回顾(10.23-10.29)
    热点随笔:· C#winform软件实现一次编译,跨平台windows和linux兼容运行,兼容VisualStudio原生界面Form表单开发 (j.king)· 那个热血澎湃的少年,他居然顶不住了! (刘牌)· Net高级调试之一:开始认识一些调试工具 (可均可可)· 浅析C#Console控制台为什么也会卡死 (一线码......
  • 11月第一周学习计划(2023/10/29 )
    科目大类学习科目 言语标题填入  态度理解  道理解释  词句理解  提炼关键词 逻辑推理逻辑论证之归因论证 申论分析理解题目 每项需要完成事件1.看完相关网课,每一个部分整理笔记并且形成博......