【分块 差分数组 逆元】3655区间乘法查询后的异或 II|2454

本文涉及知识点

数论:质数、最大公约数、菲蜀定理
C++差分数组

分块

3655. 区间乘法查询后的异或 II

给你一个长度为 n 的整数数组 nums 和一个大小为 q 的二维整数数组 queries,其中 queries[i] = [li, ri, ki, vi]。

对于每个查询,需要按以下步骤依次执行操作:

设定 idx = li。

当 idx <= ri 时:

更新:nums[idx] = (nums[idx] * vi) % (10^9 + 7)。

将 idx += ki。

在处理完所有查询后,返回数组 nums 中所有元素的 按位异或 结果。

示例 1:

输入: nums = [1,1,1], queries = [[0,2,1,4]]

输出: 4

解释:

唯一的查询 [0, 2, 1, 4] 将下标 0 到下标 2 的每个元素乘以 4。

数组从 [1, 1, 1] 变为 [4, 4, 4]。

所有元素的异或为 4 ^ 4 ^ 4 = 4。

示例 2:

输入: nums = [2,3,1,5,4], queries = [[1,4,2,3],[0,2,1,2]]

输出: 31

解释:

第一个查询 [1, 4, 2, 3] 将下标 1 和 3 的元素乘以 3,数组变为 [2, 9, 1, 15, 4]。

第二个查询 [0, 2, 1, 2] 将下标 0、1 和 2 的元素乘以 2,数组变为 [4, 18, 2, 15, 4]。

所有元素的异或为 4 ^ 18 ^ 2 ^ 15 ^ 4 = 31。

提示:

1 < = n = = n u m s . l e n g t h < = 1 0 5 1 <= n == nums.length <= 10^5 1<=n==nums.length<=105
1 < = n u m s [ i ] < = 1 0 9 1 <= nums[i] <= 10^9 1<=nums[i]<=109
1 < = q = = q u e r i e s . l e n g t h < = 1 0 5 1 <= q == queries.length <= 10^5 1<=q==queries.length<=105

queries[i] = [li, ri, ki, vi]

0 <= li <= ri < n

1 <= ki <= n
1 < = v i < = 1 0 5 1 <= vi <= 10^5 1<=vi<=105

分块 差分数组

如果 k i ≥ s q r t ( N ) ki \ge sqrt(N) ki≥sqrt(N),直接相乘。

diff[k][i]的值是x表示将 nums[i],nums[i+k],nums[i+2k] ⋯ \cdots ⋯ 都乘以x。

len = ( r i − l i ) ÷ k i + 1 (r_i - l_i) \div k_i+1 (ri−li)÷ki+1

rr = l i + k i × l e n l_i + k_i \times len li+ki×len

对查询i,可以:
d i f f [ k i ] [ l i ] × v i , d i f f [ k i ] [ r r ] ÷ v i diff[k_i][l_i] \times v_i,diff[k_i][rr] \div v_i diff[ki][li]×vi,diff[ki][rr]÷vi

代码

核心代码

cpp 复制代码
template<long long MOD = 1000000007,class T1 = int, class T2 = long long>
class C1097Int
{
public:
	C1097Int(T1 iData = 0) :m_iData(iData% MOD)
	{

	}
	C1097Int(T2 llData) :m_iData(llData% MOD) {

	}
	C1097Int  operator+(const C1097Int& o)const
	{
		return C1097Int(((T2)m_iData + o.m_iData) % MOD);
	}
	C1097Int& operator+=(const C1097Int& o)
	{
		m_iData = ((T2)m_iData + o.m_iData) % MOD;
		return *this;
	}
	C1097Int& operator-=(const C1097Int& o)
	{
		m_iData = ((T2)MOD + m_iData - o.m_iData) % MOD;
		return *this;
	}
	C1097Int  operator-(const C1097Int& o)const
	{
		return C1097Int(((T2)MOD + m_iData - o.m_iData) % MOD);
	}
	C1097Int  operator*(const C1097Int& o)const
	{
		return((T2)m_iData * o.m_iData) % MOD;
	}
	C1097Int& operator*=(const C1097Int& o)
	{
		m_iData = ((T2)m_iData * o.m_iData) % MOD;
		return *this;
	}
	C1097Int  operator/(const C1097Int& o)const
	{
		return *this * o.PowNegative1();
	}
	C1097Int& operator/=(const C1097Int& o)
	{
		*this *= o.PowNegative1();
		return *this;
	}
	bool operator==(const C1097Int& o)const
	{
		return m_iData == o.m_iData;
	}
	bool operator<(const C1097Int& o)const
	{
		return m_iData < o.m_iData;
	}
	C1097Int pow(T2 n)const
	{
		C1097Int iRet = (T1)1, iCur = *this;
		while (n)
		{
			if (n & 1)
			{
				iRet *= iCur;
			}
			iCur *= iCur;
			n >>= 1;
		}
		return iRet;
	}
	C1097Int PowNegative1()const
	{
		return pow(MOD - 2);
	}
	T1 ToInt()const
	{
		return ((T2)m_iData + MOD) % MOD;
	}
private:
	T1 m_iData = 0;;
};

class Solution {
		public:
			int xorAfterQueries(vector<int>& nums, vector<vector<int>>& queries) {
				typedef C1097Int<> BI;
				const int N = nums.size();
				vector<BI> bn(nums.begin(),nums.end());				;
				const int K = sqrt(N);
				vector<vector<BI>> diff(K, vector<BI>(N,1));
				for (auto& v : queries) {
					if (v[2] >= K) {
						for (int i = v[0]; i <= v[1]; i += v[2]) {
							bn[i] *= v[3];
						}
					}
					else {
						const int len = (v[1] - v[0]) / v[2] + 1;
						const int rr = v[0] + v[2] * len;
						diff[v[2]][v[0]] *= v[3];
						if (rr < N) {
							diff[v[2]][rr] /= v[3];
						}
					}
				}
				for (int k = 0; k < K; k++) {
					for (int k1 = 0; k1 < k; k1++) {
						BI tmp = 1;
						for (int k2 = k1; k2 < N; k2 += k) {
							tmp *= diff[k][k2];
							bn[k2] *= tmp;
						}
					}
				}
				int ans = 0;
				for (auto& bi : bn) {
					ans ^= bi.ToInt();
				}
				return ans;
			}
		};

单元测试

cpp 复制代码
vector<int> nums;
		vector<vector<int>> queries;
		TEST_METHOD(TestMethod11)
		{
			nums = { 1,1,1 }, queries = { {0,2,1,4} };
			auto res = Solution().xorAfterQueries(nums, queries);
			AssertEx(4, res);
		}
		TEST_METHOD(TestMethod12)
		{
			nums = { 2,3,1,5,4 }, queries = { {1,4,2,3},{0,2,1,2} };
			auto res = Solution().xorAfterQueries(nums, queries);
			AssertEx(31, res);
		}

扩展阅读

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

视频课程

先学简单的课程,请移步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++**实现。

相关推荐
葛小白13 小时前
C#进阶12:C#全局路径规划算法_Dijkstra
算法·c#·dijkstra算法
前端小L3 小时前
图论专题(五):图遍历的“终极考验”——深度「克隆图」
数据结构·算法·深度优先·图论·宽度优先
CoovallyAIHub3 小时前
超越像素的视觉:亚像素边缘检测原理、方法与实战
深度学习·算法·计算机视觉
CoovallyAIHub3 小时前
中科大西工大提出RSKT-Seg:精度速度双提升,开放词汇分割不再难
深度学习·算法·计算机视觉
gugugu.3 小时前
算法:位运算类型题目练习与总结
算法
百***97643 小时前
【语义分割】12个主流算法架构介绍、数据集推荐、总结、挑战和未来发展
算法·架构
代码不停3 小时前
Java分治算法题目练习(快速/归并排序)
java·数据结构·算法
bubiyoushang8884 小时前
基于MATLAB的马尔科夫链蒙特卡洛(MCMC)模拟实现方法
人工智能·算法·matlab
玖剹4 小时前
穷举 VS 暴搜 VS 深搜 VS 回溯 VS 剪枝
c语言·c++·算法·深度优先·剪枝·深度优先遍历