首页 > 其他分享 >P8818 [CSP-S 2022] 策略游戏 题解

P8818 [CSP-S 2022] 策略游戏 题解

时间:2023-12-14 23:26:39浏览次数:40  
标签:min int 题解 P8818 负数 选择 2022 max 区间

P8818 [CSP-S 2022] 策略游戏 题解

题目链接

P8818 [CSP-S 2022] 策略游戏

简化题意

小 \(A\) 先在 \(a[l1,r1]\) 中选择一个数 \(x\),小 \(B\) 再在 \(b[l2,r2]\) 中选择一个数 \(y\),最后的分数就是 \(x \times y\)。

小 \(A\) 想让分数尽可能地大,而小 \(B\) 则想让分数尽可能地小,问最后的分数会是多少。

简要思路

分情况讨论:

  • 当 \(x \ge 0\) 时,小 \(B\) 一定会选择一个最小的 \(y\);

  • 当 \(x < 0\) 时,小 \(B\) 一定会选择一个最大的 \(y\)。

再来考虑小 \(A\) 的选择情况,同样是分类讨论:

  • 当 \(x \ge 0\) 时,因为小 \(B\) 会选择最小的 \(y\),所以:

    • 当 \(y \ge 0\) 时,小 \(A\) 会让 \(x\) 更大,因为正数 \(\times\) 正数 \(=\) 正数;

    • 当 \(y < 0\) 时,小 \(A\) 会让 \(x\) 更小,即选择最小的非负数(因为现在讨论的是 \(x \ge 0\) 的情况),因为负数 \(\times\) 正数 \(=\) 负数。

  • 当 \(x < 0\) 时,因为小 \(B\) 会选择最大的 \(y\),所以:

    • 当 \(y \ge 0\) 时,小 \(A\) 会让 \(x\) 更大,即选择最大的负数(同理,因为现在讨论的是 \(x < 0\) 的情况),因为正数 \(\times\) 负数 \(=\) 负数;

    • 当 \(y < 0\) 时,小 \(A\) 会让 \(x\) 更小,因为负数 \(\times\) 负数 \(=\) 正数。

综上所述,小 \(A\) 对数的选择只有四种:

  1. 选择区间内最大的数;

  2. 选择区间内最小的非负数;

  3. 选择区间内最大的负数;

  4. 选择区间内最小的数。

因此我们只需要分别讨论得到小 \(A\) 的这四种选择在小 \(B\) 经过选择后的最优解即可。

而因为我们也要考虑小 \(B\) 对答案的最优解,所以我们要维护六个区间最值,即六个 ST 表:

  1. \(a\) 区间内的最大值;

  2. \(a\) 区间内的最小值;

  3. \(a\) 区间内的最小非负数(开始时将其赋值为一个极大值(因为维护时取最小值),从而方便判断该区间内是否有非负数);

  4. \(a\) 区间内的最大负数(同理,开始时赋为一个极小值(因为维护时取最大值),从而方便判断该区间内是否有负数);

  5. \(b\) 区间内的最大值;

  6. \(b\) 区间内的最小值。

剩下部分就是 ST 表的板子了,这里放个 ST 表的讲解:

数据结构之ST表 详解

完整代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
const int MAXN=1e5+5;
const int MAX_log=25;
const int MAX=LONG_LONG_MAX;//极值

int n,m,q;
int l1,r1,l2,r2;
int lg[MAXN];//log(i)=lg[i] 即 2^(lg[i])<=i
int a[MAXN],b[MAXN];
//6 个 ST 表(第一维起点,第二维长度[2^j])
int a_max[MAXN][MAX_log];//a 区间最大值
int a_min[MAXN][MAX_log];//a 区间最小值
int b_max[MAXN][MAX_log];//b 区间最大值
int b_min[MAXN][MAX_log];//b 区间最小值
int af_max[MAXN][MAX_log];//a 负数区间最大值
int az_min[MAXN][MAX_log];//a 非负数区间最小值

signed main(){
	std::cin>>n>>m>>q;
	
//---------ST 表的预处理---------
	for(int i=1;i<=n;i++){
		std::cin>>a[i];
		a_max[i][0]=a_min[i][0]=a[i];
		if(a[i]<0){
			af_max[i][0]=a[i];
			az_min[i][0]=MAX;//暂时没有非负数
		}else{
			af_max[i][0]=-MAX;//暂时没有负数
			az_min[i][0]=a[i];
		}
	}

	for(int i=1;i<=m;i++){
		std::cin>>b[i];
		b_max[i][0]=b_min[i][0]=b[i];
	}
	
//---------lg 数组的预处理---------
	for(int i=2;i<=std::max(n,m)+2;i++)
		lg[i]=lg[i/2]+1;

//---------倍增思想(分开)的维护
	for(int j=1;j<=lg[n];j++)//枚举区间长度
		for(int i=1;i+(1<<j)-1<=n;i++){//枚举区间起点(注意先长度再起点)
		    int now=i+(1<<(j-1));//第一个区间终点-1、第二个区间起点
		    a_max[i][j]=std::max(a_max[i][j-1],a_max[now][j-1]);
		    af_max[i][j]=std::max(af_max[i][j-1],af_max[now][j-1]);
			a_min[i][j]=std::min(a_min[i][j-1],a_min[now][j-1]);
			az_min[i][j]=std::min(az_min[i][j-1],az_min[now][j-1]);
			//以 i 为起点 长度为 2^j
			//以 i 为起点 长度为 2^(j-1)
			//以 i+2^(j-1) 为起点 长度为 2^(j-1)
		}

    for(int j=1;j<=lg[m];j++)//区间长度
		for(int i=1;i+(1<<j)-1<=m;i++){//区间起点
			int now=i+(1<<(j-1));
			b_max[i][j]=std::max(b_max[i][j-1],b_max[now][j-1]);
			b_min[i][j]=std::min(b_min[i][j-1],b_min[now][j-1]);//同上
		}

//---------ST 表的查询---------
//两个 2的幂 覆盖整个序列 a a ab ab b b
	while(q--){
		std::cin>>l1>>r1>>l2>>r2;
		int alg=lg[r1-l1+1],blg=lg[r2-l2+1];//a,b 序列的长度 2^alg 2^blg
		int sta=r1-(1<<alg)+1,stb=r2-(1<<blg)+1;//后一个区间起点=终点-区间长度+1

		int A_max=std::max(a_max[l1][alg],a_max[sta][alg]);
		int Af_max=std::max(af_max[l1][alg],af_max[sta][alg]);
		int A_min=std::min(a_min[l1][alg],a_min[sta][alg]);
		int Az_min=std::min(az_min[l1][alg],az_min[sta][alg]);
		//前一个区间(以 l1 开头 长度为 alg)
		//后一个区间(以 sta 开头,长度为 alg)
		int B_max=std::max(b_max[l2][blg],b_max[stb][blg]);
		int B_min=std::min(b_min[l2][blg],b_min[stb][blg]);
		//前一个区间(以 l2 开头 长度为 blg)
		//后一个区间(以 stb 开头,长度为 blg)

		int maxn=-MAX;

		//分类讨论正负性,考虑小 B 的最优选择
		maxn=std::max(maxn,A_max*(A_max>=0?B_min:B_max));
		maxn=std::max(maxn,A_min*(A_min>=0?B_min:B_max));
		if(Af_max!=-MAX)maxn=std::max(maxn,Af_max*(Af_max>=0?B_min:B_max));//有负数才更新
		if(Az_min!=MAX)maxn=std::max(maxn,Az_min*(Az_min>=0?B_min:B_max));//有非负数才更新

		std::cout<<maxn<<endl;
	}
	return 0;
}

标签:min,int,题解,P8818,负数,选择,2022,max,区间
From: https://www.cnblogs.com/CheZiHe929/p/17902425.html

相关文章

  • 【misc】[西湖论剑 2022]mp3 --js代码,mp3隐写,lsb隐写
    附件下载下来是一个mp3文件,我这里是先试了一下MP3Stego对mp3进行空密码解密发现得到了一个txt,貌似像一个key然后kali中foremost一下mp3,发现得到一张png图片,然后再zsteg查看这张图片‘发现有zip文件,提取出来试一下然后用一开始得到的key可以解密这个加密的压缩包,得到一段加......
  • 【专题】2022年中国跨境电商行业研究报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32044近年来,我国的跨境电子商务发展迅速,在过去五年中,其贸易额增长率达到了16.2%,已经成为稳定对外贸易的一支重要力量。阅读原文,获取专题报告合集全文,解锁文末52份跨境电商行业相关报告。一方面,随着跨境电子商务的发展,跨境电子商务的监管政策得到了......
  • 【问题解决】unable to do port forwarding: socat not found
    问题复现前阵子应公司要求做华为云平台的调研,写了一篇文档包含将华为云CCE下载kuberctl配置及使用kubectl转发流量到本地的操作。今天一早上同事就发来一个错误界面,说是Java远程调试转发过来的端口出现问题,如下图:处理思路最初以为是容器镜像未安装socat所致,安装重新打镜像后......
  • 12月13日80端口被占用问题解决
    在写软件构造作业的时候,发现Jfinal提示java.lang.IllegalStateException:port:80notavailable!原因是因为我们的80端口被占用了,当我们输入localhost的时候出现的是windows iis服务的界面这个时候需要我们关闭windowsiis服务1.点击开始收索服务,在服务界面找到worldWide......
  • luogu1972题解
    还是先写被卡的做法吧。节点的区间用了现用现计算卡常过了。被卡了一上午,难过。话说有人说我码风有点抽象。思路主席树做法。a[i]是贝壳序列。先求出nxt,即与a[i]相同的下一个a[j]的下标j。用p114514[i]记了值为\(i\)的数的下标,循环到序列第\(j\)个数的时候,先......
  • Vue + Element UI 实现复制当前行数据功能(复制到新增页面组件值不能更新等问题解决)
    1、需求使用Vue+ElementUI实现在列表的操作栏新增一个复制按钮,复制当前行的数据可以打开新增弹窗后亦可以跳转到新增页面,本文实现为跳转到新增页面。2、实现1)列表页index.vue<el-table><!--其他列--><el-table-columnlabel="操作"width="150"><templateslot-scope=......
  • vs2022 vim配置
    参考:Vs中使用Vim模式_vsvim-CSDN博客,其他待补充 ......
  • [good]visual studio 2022 创建空的win32程序
    参考这个VS创建空的Win32程序-fenggwsx-博客园(cnblogs.com)   编译运行 ......
  • [CF980D] Perfect Groups 题解
    [CF980D]PerfectGroups题解思路第一个观察就很难观察到:\[ab=x^2,bc=y^2\Longrightarrow\existz,ac=z^2(a,b,c\ne0)\]证明:两个条件式相乘得到:\[ab^2c=x^2y^2\\ac=\dfrac{x^2y^2}{b^2}(b\ne0)\\\becauseb|x^2,b|y^2\\\thereforeb^2|x^2y^2......
  • P1004 [NOIP2000 提高组] 方格取数 题解
    P1004[NOIP2000提高组]方格取数题解题目链接P1004[NOIP2000提高组]方格取数简要思路注意一下输入可以简化为while(std::cin>>x>>y>>val&&x){ //***}运用DP的思想。用一个四维的\(DP\)数组\(dp[i][j][k][l]\)来同时记录两条路径分别走到\((i,j)\)和\((k,......