【分治法 前缀和】P8572 [JRKSJ R6] Eltaw|普及+

本文涉及的基础知识点

C++算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频

分治法

[JRKSJ R6] Eltaw

题目背景

你在月下独自行走,不禁想起了一道简单题。

(题目背景图片来自 Phigros 曲绘,如有侵权,请告知出题人。)

题目描述

给你 k k k 个长为 n n n 的序列 a 1 ... k , 1 ... n a_{1\dots k,1\dots n} a1...k,1...n,有 q q q 次询问,每次询问给出一个区间 [ l , r ] [l,r] [l,r],要求出 max ⁡ i = 1 k ∑ j = l r a i , j \displaystyle\max_{i=1}^k\sum_{j=l}^ra_{i,j} i=1maxkj=l∑rai,j,即求出所有序列中区间 [ l , r ] [l,r] [l,r] 的和的最大值。

输入格式

第一行三个整数 n , k , q n,k,q n,k,q。

接下来 k k k 行,每行 n n n 个整数 a i , j a_{i,j} ai,j。

接下来 q q q 行,每行两个整数 l , r l,r l,r 表示一次询问。

输出格式

输出 q q q 行表示每个询问的答案。

样例 #1

样例输入 #1

复制代码
7 2 3
1 1 4 5 1 4 0
1 9 1 9 8 1 0
6 7
5 7
1 3

样例输出 #1

复制代码
4
9
11

提示

Idea:cyffff,Solution:cyffff,Code:cyffff,Data:cyffff

Eltaw - Fl00t (Insane14.4)

本题输入输出文件较大,请使用恰当的输入输出方式。

数据规模

本题采用捆绑测试。

Subtask \text{Subtask} Subtask n ≤ n\le n≤ 特殊限制 Score \text{Score} Score
1 1 1 5 × 10 3 5\times10^3 5×103 k ≤ 100 k\le 100 k≤100 20 20 20
2 2 2 5 × 10 5 5\times10^5 5×105 保证 l = 1 l=1 l=1 30 30 30
3 3 3 5 × 10 5 5\times10^5 5×105 50 50 50

对于 100 % 100\% 100% 的数据, 1 ≤ n , k , q ≤ 5 × 10 5 1\le n,k,q\le5\times 10^5 1≤n,k,q≤5×105, 1 ≤ n × k ≤ 5 × 10 5 1\le n\times k\le 5\times10^5 1≤n×k≤5×105, 1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1≤l≤r≤n, 0 ≤ a i , j ≤ 10 9 0\le a_{i,j}\le 10^9 0≤ai,j≤109。

数据更新记录

upd 2022.10.05 \text{upd 2022.10.05} upd 2022.10.05:更新了两组数据,分别卡掉了两种时间复杂度错误的做法。感谢 @二叉苹果树 指出。

upd 2022.10.08 \text{upd 2022.10.08} upd 2022.10.08:更新了一组数据,卡掉了记忆化不正确的做法。感谢 @SweetOrangeOvO 指出。

如果你能通过现在的所有测试点,说明你的代码复杂度极可能是正确的。如果你仍认为你的复杂度是错误的,请联系出题人。

前缀和

方式一

L--,R--

preSum[i]记录第i个数列的前缀和。每次查询时,枚举preSum[i][R+1]-preSum[i][L]的最大值,单个查询时间复杂度:O(k),总时间复杂度:O(kq)

预处理

ans[L][R]记录 查询(L,R)的结果。

空间复杂度:O(nn), 时间复杂度:O(nnk)

处理方法

n <=1000,采用预备处理 ,时间复杂度大约 1000 nk ,由于L必须小于等于R,故状态数减半。500nk = 2.5e8。 本题时间2s,能过。

n >= 1000,则k <=500,采用方式一 2.5e8。

用C++的代码超时

cpp 复制代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for(int i=0;i < n ;i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

class Solution {
public:
	vector<long long> Ans(vector<vector<int>>& mat, vector<pair<int, int>>& que) {
		const int K = mat.size(), N = mat[0].size(), Q = que.size();
		vector<vector<long long>> preSum(K, vector<long long>(1));
		for (int k = 0; k < K; k++) {
			for (int n = 0; n < N; n++) {
				preSum[k].emplace_back(preSum[k].back() + mat[k][n]);
			}
		}
		vector<long long> ans;
		if (N <= 1000) {
			vector<vector<long long>> vInit(N, vector<long long >(N));
			for (int left = 0; left < N; left++) {
				for (int r = left; r < N; r++) {
					for (auto ps : preSum) {
						vInit[left][r] = max(vInit[left][r], ps[r + 1] - ps[left]);
					}
				}
			}
			for (const auto& [left, r] : que) {
				ans.emplace_back(vInit[left - 1][r - 1]);
			}
			return ans;
		}
		for (auto [left, r] : que) {
			long long cur = 0;
			for (auto ps : preSum) {
				cur = max(cur, ps[r] - ps[left - 1]);
			}
			ans.emplace_back(cur);
		}
		return ans;
	}
};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	int k,n,q;
	cin >> n >>k  >> q;
	vector<vector<int>> mat(k, vector<int>(n));
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &mat[i][j]);
		}
	}
	auto que = Read<pair<int,int>>(q);	
#ifdef _DEBUG	
	//printf("N=%d", n);
	//Out(mat, "mat=");
	//Out(que, ",que=");
#endif	
	auto res = Solution().Ans(mat,que);
	for (const auto& i : res) {
		printf("%lld\r\n", i);
	}
	return 0;
}

将前缀和换长C方式就可以

用 new long long[...]也可以

cpp 复制代码
#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for(int i=0;i < n ;i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

class Solution {
public:
	vector<long long> Ans(vector<vector<int>>& mat, vector<pair<int, int>>& que) {		
		const int K = mat.size(), N = mat[0].size();
		long long preSum[(int)1e6 + 10];
		for (int k = 0; k < K; k++) {
			preSum[(N + 1) * k] = 0;
			for (int n = 0; n < N; n++) {
				preSum[(N + 1) * k + n + 1] = preSum[(N + 1) * k + n] + mat[k][n];
			}
		}
		vector<long long> ans(que.size());
		if (K >= 500) {
			vector<vector<long long>> vInit(N, vector<long long >(N));
			for (int left = 0; left < N; left++) {
				for (int r = left; r < N; r++) {
					for (int k = 0; k < K;k++) {
						vInit[left][r] = max(vInit[left][r], preSum[(N+1)*k+r+1] - preSum[(N + 1) * k + left]);
					}
				}
			}
			int i = 0;
			for (const auto& [left, r] : que) {
				ans[i++] = vInit[left - 1][r - 1];
			}
			return ans;
		}
		int i = 0;
		for (const auto& [left, r] : que) {			
			for (int k = 0; k < K; k++) {
				ans[i] =max(ans[i], preSum[(N + 1) * k + r] - preSum[(N + 1) * k + left-1]);
			}
			i++;
		}
		return ans;
	}
};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	int k,n,q;
	cin >> n >>k  >> q;
	vector<vector<int>> mat(k, vector<int>(n));
	for (int i = 0; i < k; i++) {
		for (int j = 0; j < n; j++) {
			scanf("%d", &mat[i][j]);
		}
	}
	vector<pair<int, int>> que(q);
	for (int i = 0; i < q; i++) {
		scanf("%d%d",&que[i].first,&que[i].second);
	}
#ifdef _DEBUG	
	//printf("N=%d", n);
	//Out(mat, "mat=");
	//Out(que, ",que=");
#endif	
	auto res = Solution().Ans(mat,que);
	for (const auto& i : res) {
		printf("%lld\r\n", i);
	}
	return 0;
}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。

相关推荐
纤纡.2 小时前
矿物识别分类:8 种机器学习算法对比与实战(平均值填充数据集)
python·深度学习·算法·机器学习
ulias2122 小时前
函数栈帧的创建和销毁
开发语言·数据结构·c++·windows·算法
少许极端2 小时前
算法奇妙屋(三十五)-贪心算法学习之路 2
学习·算法·贪心算法
代码探秘者2 小时前
【算法篇】3.位运算
java·数据结构·后端·python·算法·spring
Aaswk2 小时前
回溯算法的本质理解
c语言·算法·leetcode·力扣·剪枝
迷海2 小时前
力扣原题《分发糖果》,采用二分原则,纯手搓,待验证
c++·算法·leetcode
玛卡巴卡ldf2 小时前
【LeetCode 手撕算法】(普通数组)53-最大子数组和、56-合并区间、189-轮转数组、238-除了自身以外数组的乘积
数据结构·算法·leetcode
Trouvaille ~2 小时前
【项目篇】从零手写高并发服务器(七):定时器TimerWheel与线程池
运维·服务器·网络·c++·reactor·高并发·muduo库
j_xxx404_2 小时前
蓝桥杯基础--模拟
数据结构·c++·算法·蓝桥杯·排序算法