• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Augenstern-
博客园    首页    新随笔    联系   管理    订阅  订阅
2025.9.26 测试

今天考 shanganze 大蛇的

菜菜...

T1

P10102 [GDKOI2023 提高组] 矩阵

暴力就 \(n^3\) 判断

思考正解 :

发现矩阵乘法的过程很典,我们肯定不能优化 我要优化矩乘

那我们可以想类似哈希,将信息压缩

我想到两种

第一种,也是先想到的

算出 \(c\) 矩阵的行列和,与 \(a \times b\) 比较即可

有人就要问了,这不是 \(n^3\) 的 ?

观察矩阵乘法形式,用前缀和优化即可 (\(n ^ 3\))

但这个显然会被卡(好像不容易被赛事卡),而且需要额外的前缀和数组,常数还大

有没有什么更简单的做法

有的有的

考虑矩阵乘是 \(n^3\) 的,但向量就 \(n^2\)

可以随一个向量验证

正确性很高

AC

T2

P12479 [集训队互测 2024] 长野原龙势流星群

注意题目是让求每个子树(我读错了)

很厉害的题目

暴力可以写 \(O(n ^ 2)\) 的背包,然后发现是个闵和的形式,听说可以用平衡树维护

但常数有亿点大

正解是贪心

考虑最大的点一定只选自己,而操作其父亲时,一定会选他,那我们就可以直接将他和父亲合并

一个点被合并时就是答案

相当于是一个不断选最大点的过程

用并查集和优先队列维护即可

AC

T3

P13523 [KOI 2025 #2] 序列与查询

题目很明了 先打个暴力

发现一段区间的贡献与区间和和长度有关

相同长度的区间只有最大值有用

那我们可以直接将信息压缩,假设我们已经得到任意长度和的最大值

发现询问就是若干一次函数求最大值,就是李超树的形式

但短暂思考,我们也可以用更为简单的单调队列实现

询问复杂度单次 \(log\) , 够用

关键在于预处理

要求出所有长度,考虑分治

每次处理跨区间的贡献,处理两边的前后缀和数组 \(f , g\),答案形式如下

\(h_{i + j}\) <- \(max(f_i + g_j)\)

是标准闵可夫斯基和形式

但 \(f , g\) 不是凸函数,但发现若不在凸包上一定不在最后的答案数组上,所以可以直接求凸包

AC

T4.

CF2023F Hills and Pits

区间和 \(< 0\) 即无解,否则一定有解

这题考虑答案不超过 \(2 \times len\) ,因为可以走来回,一定合法

考虑怎样减少代价

假设 \(s \le t\) ,由于每个位置都要经过,所以 \(\le s , \ge t\),最优即为经过两遍

设 \(sum_x\) 表示,左端点 \(l\) 到 \(x\) 的和

而他们中间,如果一个点 \(x\) , \(sum_x \ge 0\) 那只用经过一遍

而 \(sum_x < 0\) 最优一定是到后面最近的一个 \(sum_y \le 0\) ,再回来绕一遍,需要走三遍

那贡献就明了了,把前缀和 \(\le 0\) 的位置赋成 1 , 否则赋成 -1 ,走两遍减去最大区间和

对 \(sum_{l - 1}\) 扫描线

然后小白逛公园即可

注意我们是对 \(s \le t\) 讨论,实际上我们只需要正反做两遍即可

点击查看代码
/* みやみず みつは */
/* 任何错误都有迹可循 */
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 3e6 + 10;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int n , m;
int h[N] , sum[N];
struct qii {
	int l , r , h , id;
}qm[N]; int cnt;
int ans[N] , id[N];
bool cmp(qii x , qii y) { return x.h < y.h; }
bool hhh(int x , int y) { return sum[x] < sum[y]; }
struct seg {
	int lmx , rmx , mx , sum;
	void init(int tg) { lmx = rmx = mx = sum = tg; }
	seg operator + (const seg &x) const {
		return (seg){max(lmx , sum + x.lmx) , max(x.rmx , rmx + x.sum) ,
			 max({mx , x.mx , rmx + x.lmx}) , sum + x.sum};
	}
}t[N];
#define mid (l + r) / 2
#define ls p << 1
#define rs p << 1 | 1
void pushup(int p) { t[p] = t[ls] + t[rs]; }
void build(int p , int l , int r) {
	if(l == r) { t[p].init(1); return ; }
	build(ls , l , mid); build(rs , mid + 1 , r);
	pushup(p);
}
void mdf(int p , int l , int r , int x) {
	if(l == r) { t[p].init(-1); return ; }
	if(x <= mid) mdf(ls , l , mid , x);
	else mdf(rs , mid + 1 , r , x);
	pushup(p);
}
seg qry(int p , int l , int r , int x , int y) {
	if(l >= x && r <= y) return t[p];
	if(y <= mid) return qry(ls , l , mid , x , y);
	if(x > mid) return qry(rs , mid + 1 , r , x , y);
	return qry(ls , l , mid , x , y) + qry(rs , mid + 1 , r , x , y);
}

void init() {
	cnt = 0;
	for(int i = 1;i <= n;i ++) id[i] = i;
	for(int i = 1;i <= m;i ++) ans[i] = 1e18;
}
void rev() {
	reverse(h + 1 , h + n + 1);
	for(int i = 1;i <= cnt;i ++) qm[i].l = n - qm[i].l + 1 , qm[i].r = n - qm[i].r + 1;
	for(int i = 1;i <= cnt;i ++) swap(qm[i].l , qm[i].r);
}
void ii() {
	build(1 , 1 , n);
	for(int i = 1;i <= n;i ++) sum[i] = h[i] + sum[i - 1];
	for(int i = 1;i <= cnt;i ++) qm[i].h = sum[qm[i].l - 1];
	sort(qm + 1 , qm + cnt + 1 , cmp);
	sort(id + 1 , id + n + 1 , hhh);
	int H = 1;
	for(int i = 1;i <= cnt;i ++) {
		while(H <= n && sum[id[H]] < qm[i].h) mdf(1 , 1 , n , id[H]) , H ++;
		ans[qm[i].id] = min(ans[qm[i].id] , 
			-qry(1 , 1 , n , qm[i].l , qm[i].r - 1).mx + 2 * (qm[i].r - qm[i].l));
	}
	
}

signed main() {
	int T; T = read();
	while(T --) {
		n = read(); m = read(); init();
		for(int i = 1;i <= n;i ++) h[i] = read();
		for(int i = 1;i <= n;i ++) sum[i] = h[i] + sum[i - 1];
		for(int i = 1;i <= m;i ++) {
			int l = read() , r = read();
			if(sum[r] - sum[l - 1] < 0) { ans[i] = -1; continue; }
			if(l == r) { ans[i] = 0; continue; }
			qm[++ cnt] = (qii) {l , r , sum[l - 1] , i};
		}
		ii(); rev(); ii();
		for(int i = 1;i <= m;i ++) printf("%lld\n",ans[i]);
	}
	return 0;
}
posted on 2025-09-26 23:02  初绘  阅读(6)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3