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

本文涉及知识点

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

分块

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

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

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

设定 idx = li。

当 idx <= ri 时:

更新:numsidx = (numsidx * 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 <= numsi <= 10^9 1<=numsi<=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

queriesi = 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),直接相乘。

diffki的值是x表示将 numsi,numsi+k,numsi+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 diffk_il_i \times v_i,diffk_irr \div v_i diffkili×vi,diffkirr÷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++**实现。

相关推荐
想吃火锅100511 分钟前
【leetcode】14.最长公共前缀js
算法·leetcode·职场和发展
Roann_seo%15 分钟前
C++文件操作完全指南:从文本读写到二进制文件处理
开发语言·c++
坚果派·白晓明1 小时前
【鸿蒙PC】SDL3 适配:AtomCode + Skills 快速集成 NAPI 测试工具
c++·华为·ai编程·harmonyos·atomcode
云絮.1 小时前
数据库操作
数据库·mysql·算法·oracle
小林ixn2 小时前
LeetCode 206. 反转链表(迭代 + 递归详解)
算法·leetcode·链表
凡人叶枫2 小时前
Effective C++ 条款17:以独立语句将 newed 对象置入智能指针
java·linux·开发语言·c++·算法
凡人叶枫3 小时前
Effective C++ 条款16:成对使用 new 和 delete 时要采取相同形式
开发语言·c++·effective c++
菜鸟‍3 小时前
LeetCode 1 27 和 704 || 两数之和 移除元素 二分查找
算法·leetcode·职场和发展
不吃土豆的马铃薯3 小时前
C++ 高性能网络缓冲区 Buffer 源码解析
linux·服务器·开发语言·网络·c++
.千余4 小时前
【C++】C++继承入门(下):友元、静态成员与菱形继承的底层逻辑
开发语言·c++·笔记·学习·其他