2-2基础算法-Nim和/前缀和/差分

文章目录

  • 一.Nim和
  • 二.前缀和&区间和
  • 三.差分

一.Nim和

Nim游戏是一个数学策略游戏,通常涉及两名玩家轮流从几堆物品(如石子或饼干)中取走一定数量的物品。每个玩家每次可以从任意一堆中取走任意数量的物品,但必须至少取走一个。最后无法进行操作的玩家输掉游戏。

Nim和是所有堆中物品数量的二进制异或(XOR)结果。在计算Nim和时,我们将每堆物品的数量转换为二进制数,然后对这些二进制数进行异或运算。例如,如果有三堆物品,数量分别是3、5、7,则它们的二进制表示分别是011、101、111。它们的Nim和是011 XOR 101 XOR 111 = 001。

在标准的Nim游戏中,如果Nim和为0,那么当前的局面对于后手(即非当前回合的玩家)是有利的,因为后手可以通过策略性地取物品,始终保持Nim和为0的状态,直到游戏结束。如果Nim和非0,先手(当前回合的玩家)处于优势,因为他们可以通过一次操作改变堆的状态,使Nim和变为0,从而控制游戏进程。

[例] Alice和Bob的爱恨情仇

在这里插入图片描述
在这里插入图片描述

评测系统

分析:此题游戏规则中有额外的限制(每次只能取走k的奇数倍的物品),我们需要对标准Nim游戏的策略进行调整。我们可以通过检查每堆中物品的数量是否可以通过取走k的奇数倍来减少到Nim和的值,从而确定哪位玩家拥有获胜策略。

#include <iostream>
#include <vector>
using namespace std;
int power(int base, int exp) {
    int result=1;
    while (exp) {
        result = result * base;
        exp--;
    }
    return base;
}
bool canwin(int a[], int n, int k) {
    int nimsum = 0;
    for (int i = 0; i < n; i++) {
        nimsum = nimsum ^ a[i];//异或^
    }
    if (nimsum == 0)
        return false;
    for (int i = 0; i < n; i++) {
        int num = a[i];//第i堆饼干数量
        for (int j = 1; power(j,k) <= num; j+=2) { //保证j是奇数
            if (num - power(j, k) == (nimsum ^ num)) //即:如果if条件满足,那么当前玩家可以通过这次移动使得整个游戏的Nim和变为0
                return true;
        }
    }
    return false;
}
int main()
{
    int n, k;
    cin >> n >> k;
    int a[2000005];
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    bool wins = canwin(a, n, k);
    cout<<(wins ? "Alice" : "Bob");
}

二.前缀和&区间和

1.前缀和原理和特点
定义:(类似于前n项和)
prefix[0]=0
在这里插入图片描述
性质:
在这里插入图片描述
前缀和可以在O(1)的复杂度处理一段区间的和
如:数组l到r的和,等于p[r]-p[l-1]
在这里插入图片描述
2.例题
(1)区间次方和

在这里插入图片描述
在这里插入图片描述

评测系统

常规方式可能超时

由于k比较小,我们可以定义5个数组,分别表示原数组的1~5次幂,然后只需输出l ~ r之间元素的和即可。整个过程可以借助二维数组实现。此方法仍然会超时

再加上前缀和

#include <iostream>
#include <vector>
using namespace std;
const int value= 1e9+7;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	long long arr[6][100005];
	for (int i = 1; i <= n; i++) { //输入与k次方
		cin >> arr[1][i];
		for (int k = 2; k <= 5; k++) {
			arr[k][i] = arr[k - 1][i] * arr[1][i]%value;
		}
	}
	long long prefix[6][100005];//前缀和数组
	for (int i = 1; i <= 5; i++) {
		for (int j = 1; j <= n; j++) {
			prefix[i][j] = (prefix[i][j - 1] + arr[i][j]) % value;
		}
	}
	while (m--) {
		int a, b, c;
		cin >> a >> b >> c;
		//在计算过程中对每个元素都取模,会导致后面元素不一定大于前面元素
		//最终结果仍要取模,并考虑负数的出现
		cout << (prefix[c][b]-prefix[c][a-1]+value)%value << endl;
	}
}

(2)大石头的搬运工
在这里插入图片描述
在这里插入图片描述
评测系统

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int main()
{
	int n;
	cin >> n;
	pair<int, int> q[N];//初始数据
	for (int i = 1; i <= n; ++i) {
		cin >> q[i].second >> q[i].first;//first初始位置,second权重
	}
	sort(q+1, q + n+1);

	long long s = 0;
	long long prefix[N] = { 0 }; //从第一个位置到位置i的所有石头 移动到位置i的总费用
	for (int i = 1; i <= n; ++i) {
		prefix[i] =prefix[i - 1] + s * (q[i].first - q[i - 1].first);
		s += q[i].second;
	}

	s = 0;
	long long nextfix[N] = { 0 };//从位置i到最后一个位置的所有石头 移动到位置i的总费用
	for (int i = n; i >= 1; --i) {
		nextfix[i] =nextfix[i + 1]+ s * (q[i + 1].first - q[i].first);
		s += q[i].second;
	}

	long long res=1e18;
	for (int i = 1; i <= n; ++i) {
		res = min(res, prefix[i] + nextfix[i]);
	}
	cout << res;
}

(3)最大数组和
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
评测系统

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5+5;
int main()
{
	int t;
	cin >> t;
	long long sum;
	while (t--) {
		long long a[N] = { 0 };
		int n, k;
		cin >> n >> k;
		sum = 0;
		for (int i = 1; i <= n; ++i) {
			cin >> a[i];
			sum += a[i];
		}
		sort(a+1, a + n+1);
		long long pre[N] = { 0 }, nex[N] = { 0 };
		for (int i = 1; i <= n; ++i) {//前缀和
			pre[i] = pre[i - 1] + a[i];
		}
		for (int i = n; i >= 1; --i) {//后缀和
			nex[i] = nex[i + 1] + a[i];
		}
		long long temp = 1e18;
		for (int i = 0; i <= k; ++i) {
			int cntmin = i * 2;//对前面处理i次,删掉了开头的2i个数
			int cntmax = k - i;//对后面操作了k-i次,删掉了尾部的k-i个数
			temp=min(temp,pre[cntmin] + nex[n-cntmax+1]);
		}
		cout << sum - temp << endl;
	}
}

三.差分

差分的主要优势是可以快速地对原数组的一个区间内的所有元素进行同样的增加或减少操作。

1.原理
定义:差分定义为原数组相邻元素之间的差值
a[]原数组,diff差分数组
其中diff[0]=a[0]
在这里插入图片描述
性质:差分数组的前缀和等于原数组
在这里插入图片描述

如果我们想对区间[k,r]中的元素都加x
只需:
从k到数组末尾的元素都加x:diff[k]+=x
r+1及其以后的元素都减x:diff[r+1]-=x

这里diff[k]+=x的意义是,a[k]比a[k-1]多了x。a[k+1]和a[k]的差值要想保持不变,也a[k+1]也需要加x,以此类推

注:只有使用前缀和输出才是有效更新

2.练习
(1)区间更新
在这里插入图片描述
评测系统

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int main()
{
	int n, m;
	while (cin >> n >> m) {
		int a[N] = { 0 }, diff[N] = { 0 }, prefix[N] = { 0 };
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		for (int i = 1; i <= n; i++) {
			diff[i] = a[i] - a[i - 1];
		}
		while (m--) {
			int x, y, z;
			cin >> x >> y >> z;
			diff[x] += z;
			diff[y+1] -= z;
		}
		for (int i = 1; i <= n; i++) { //使用前缀和还原
			prefix[i] = prefix[i - 1] + diff[i];
		}
		for (int i = 1; i <= n; i++) {
			cout << prefix[i] << " ";
		}
		cout << endl;
	}
}

(2)小明的彩灯
在这里插入图片描述
在这里插入图片描述

评测系统

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5e5 + 5;  //修改
int main()
{
	int n, q;
	cin >> n >> q;
	long long a[N] = { 0 }, diff[N] = { 0 }, prefix[N] = { 0 };  //修改
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++) {
		diff[i] = a[i] - a[i - 1];
	}
	while (q--) {
		int x, y, z;
		cin >> x >> y >> z;
		diff[x] += z;
		diff[y + 1] -= z;
	}
	for (int i = 1; i <= n; i++) {
		prefix[i] = prefix[i - 1] + diff[i];
	}
	for (int i = 1; i <= n; i++) {  //修改
		if (prefix[i] > 0)
			cout << prefix[i] << " ";
		else
			cout << 0 <<" ";
	}
	cout << endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/246467.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Pytorch从零开始构建StyleGAN

本文介绍的是当今最好的 GAN 之一&#xff0c;来自论文《A Style-Based Generator Architecture for Generative Adversarial Networks》的 StyleGAN &#xff0c;我们将使用 PyTorch 对其进行干净、简单且可读的实现&#xff0c;并尝试尽可能接近原始论文。 如果您没有阅读过…

设计模式(二)-创建者模式(5)-建造者模式

一、为何需要建造者模式&#xff08;Builder&#xff09;? 在软件系统中&#xff0c;会存在一个复杂的对象&#xff0c;复杂在于该对象包含了很多不同的功能模块。该对象里的各个部分都是按照一定的算法组合起来的。 为了要使得复杂对象里的各个部分的独立性&#xff0c;以及…

一篇文章讲透TCP/IP协议

1 OSI 7层参考模型 2 实操连接百度 nc连接百度2次&#xff0c;使用命令netstat -natp查看就会重新连接一次百度 请求百度 3 三次握手、socket 应用层协议控制长连接和短连接 应用层协议->传输控制层&#xff08;TCP UDP&#xff09;->TCP&#xff08; 面向连接&am…

02-MQ入门之RabbitMQ简单概念说明

二&#xff1a;RabbitMQ 介绍 1.RabbitMQ的概念 RabbitMQ 是一个消息中间件&#xff1a;它接受并转发消息。你可以把它当做一个快递站点&#xff0c;当你要发送一个包裹时&#xff0c;你把你的包裹放到快递站&#xff0c;快递员最终会把你的快递送到收件人那里&#xff0c;按…

Linux-----5、文件系统

# 文件系统 # 终端的基本操作 ㈠ 打开多个终端 ㈡ 快速清屏 新建标签&#xff1a;command T 新建窗口&#xff1a;command N 关闭标签&#xff1a;command Q 关闭窗口&#xff1a;command W 放大&#xff1a;command 缩小&#xff1a;command - 清屏&#xff…

【XR806开发板试用】+2.鸿蒙内核

非常感谢基于安谋科技STAR-MC1的全志XR806 Wi-FiBLE开源鸿蒙开发板试用活动&#xff01;非常感谢极术社区&#xff01;非常感谢极术小姐姐&#xff01;非常感谢全志在线开发者社区&#xff01;非常感谢通过试用申请&#xff01;非常感谢安谋科技&#xff01; 接上一篇&#xff…

[C++] 虚函数、纯虚函数和虚析构(virtual)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/weixin_43197380&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 Loewen丶原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&…

解决nuxt3引入图片报错:ReferenceError: require is not defined

现象&#xff1a; 原因&#xff1a;在nuxt3中不支持require的方式引入图片/文件等静态资源。 解决办法&#xff1a; 1. 直接在img标签中的src属性里写明图片的路径&#xff0c;但是此时src前面不能有冒号做动态绑定&#xff01;&#xff1a; src"/assets/images/loading…

Tekton 基于 gitlab 触发流水线

Tekton 基于 gitlab 触发流水线 Tekton EventListener 在8080端口监听事件&#xff0c;Gitlab 提交代码产生push 事件&#xff0c;gitlab webhook触发tekton流水线执行。 前置要求&#xff1a; kubernetes集群中已部署 tekton pipeline、tekton triggers以及tekton dashboa…

CSS特效030:日蚀动画

CSS常用示例100专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花边是描述了一些CSS…

Amazon CodeWhisperer:AI 编程助手

文章作者&#xff1a;prigioni 1. 什么是 Amazon CodeWhisperer&#xff1f; Amazon CodeWhisperer 能够理解以自然语言&#xff08;英语&#xff09;编写的注释&#xff0c;并能实时生成多条代码建议&#xff0c;以此提高开发人员生产力。该服务可以直接在集成开发环境&#…

C# URL参数编码

string s "lw123abc测试信息&#xff01;#&#xffe5;%……&*&#xff08;&#xff09;——"; Console.WriteLine("原数据:\t\t" s); String s2 Uri.EscapeDataString(s);//Uri.EscapeDataString() 编码 Console.WriteLine("Hexdata:\t&qu…

spring 笔记五 SpringMVC的数据响应

文章目录 SpringMVC的数据响应SpringMVC的数据响应方式回写数据 SpringMVC的数据响应 SpringMVC的数据响应方式 页面跳转 直接返回字符串通过ModelAndView对象返回 回写数据 直接返回字符串返回对象或集合 返回字符串形式 直接返回字符串&#xff1a;此种方式会将返回的字符…

风速预测(四)基于Pytorch的EMD-Transformer模型

目录 前言 1 风速数据EMD分解与可视化 1.1 导入数据 1.2 EMD分解 2 数据集制作与预处理 2.1 先划分数据集&#xff0c;按照8&#xff1a;2划分训练集和测试集 2.2 设置滑动窗口大小为7&#xff0c;制作数据集 3 基于Pytorch的EMD-Transformer模型预测 3.1 数据加载&am…

2024 年 值得收藏的10 款顶级 Windows 数据恢复软件

您是否需要并搜索过某个文件或文件夹&#xff0c;却发现您最近不小心删除了它&#xff1f;或者更糟糕的是&#xff0c;您不知道文件/文件夹发生了什么&#xff0c;因为由于某种原因&#xff0c;它从您的驱动器中消失了&#xff1f;这些事情会造成伤害并且可能令人沮丧&#xff…

使用Redis构建简单的社交网站

文章目录 第1关&#xff1a;创建用户与动态第2关&#xff1a;处理用户关系第3关&#xff1a;状态与信息流 第1关&#xff1a;创建用户与动态 编程要求 在Begin-End区域编写 create_user(login_name, real_name) 函数&#xff0c;实现创建新用户的功能&#xff0c;具体参数与要…

【注解和反射】-- 02 反射

Java反射 01 概述 1.1 静态 vs 动态语言 动态语言 是一类在运行时可以改变其结构的语言&#xff1a;例如新的函数、对象、甚至代码可以被引进&#xff0c;已有的函数可以被删除或者是其他结构上的变化。通俗来说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言…

geemap学习笔记027:遥感影像指数计算,并依据研究区进行裁剪

前言 GEE最常用的一个功能就是指数的计算&#xff0c;并且可以进行较大范围的计算&#xff0c;然后根据感兴趣区进行裁剪。常见的指数有归一化差异植被指数 (NDVI)、增强植被指数 (EVI)、叶面积植被指数&#xff08;LAI&#xff09;、归一化差值水体指数(NDWI)、归一化建筑指数…

xcode 修改 target 中设备朝向崩溃

修改xcode的target中的设备朝向导致崩溃。 从日志上看好像没有什么特别的信息。 之后想了想&#xff0c;感觉这个应该还是跟xcode的配置有关系&#xff0c;不过改动的地方好像也只有plist。 就又翻腾了半天plist中的各种配置项&#xff0c;再把所有的用户权限提示相关的东西之…

Unity中Shader URP最简Shader框架(ShaderGraph 转 URP Shader)

文章目录 前言一、 我们先了解一下 Shader Graph 怎么操作1、了解一下 Shader Graph 的面板信息2、修改Shader路径3、鼠标中键 或 Alt 鼠标左键 移动画布4、鼠标右键 打开创建节点菜单5、把ShaderGraph节点转化为 Shader 代码6、可以看出 URP 和 BuildIn RP 大体框架一致 二、…
最新文章