首页 > 其他分享 >P3411 序列变换 题解

P3411 序列变换 题解

时间:2024-02-19 11:15:55浏览次数:26  
标签:1000005 P3411 int 题解 mn 序列 mx 无缝

自己做不出来,看现在题解区的题解讲的都不咋清楚。懂了之后来为后人铺路。而且我的马蜂比较好看

题目传送门

我能看懂这道题,主要是依靠了这篇题解的帮助。

首先我们只关注数的相对关系,所以可以离散化。注意到值域 \(10^6\),用数组离散化。

这道题可以用贪心做。(有一些定义先往下看)

定义一个无缝子序列:一个子序列中最小值为 \(mn\),最大值为 \(mx\),且原数组中所有值在 \([mn,mx]\) 中的数全部在子序列中,再并且这个子序列单调不减,称这个子序列是 “无缝的”。

例如原序列离散化后是 1 4 4 2 3 7 5 4 5 6,那么子序列 5 5 6 是无缝的;子序列 4 4 4 6 不是无缝的,因为 \(5\) 没有包含在子序列中;子序列 4 4 5 4 5 6 也不是无缝的,因为不单调不减。

再定义一个无缝子序列的拓展长度:假设一个无缝子序列的最小值为 \(mn\),最大值为 \(mx\),长度为 \(len\)。第一个 \(mn\) 左边有 \(cnt1\) 个 \(mn-1\)。最后一个 \(mx\) 右边有 \(cnt2\) 个 \(mx+1\)。称这个无缝子序列的拓展长度为 \(len+cnt1+cnt2\)。

现在抛出贪心的结论:答案就是 \(n-x\),\(x\) 是最大的 “无缝子序列拓展长度”。注意这里表示的不是 “最长的无缝子序列” 的拓展长度。

为什么呢?首先我们证明存在一组解,可以构造出 \(n-x\) 次操作。

假设无缝子序列 \(\{num\}\) 使得它的拓展长度为 \(x\)。

那就可以固定 \(\{num\}\) 中所有数和所有计算拓展长度时统计到的 \(mn-1\) 和 \(mx+1\)。这些数不进行操作。

剩下所有数,分成两拨:小于 \(mn\) 的和大于 \(mx\) 的。

将小于 \(mn\) 的数从大到小排序,依次将每个数放在开头;将大于 \(mx\) 的数从小到大排序,依次将每个数放在结尾。

这样每个没固定的数都使用了一次操作,共 \(n-x\) 次操作使得整个序列排好了序。

下面证明不存在比 \(n-x\) 还小的解。假设更小的解是 \(k\)。

那么说明至少有 \(n-k\) 个数没有进行操作。这些没进行操作的数一定形成一个 “无缝子序列拓展” 的形式。因为假如它中间有数没有出现,一定需要将外界的数移到中间来,这需要移动这 \(n-k\) 个数;假如它不是单调不减,需要重新排序,也需要移动这些数。

综上所述,最终的答案就是 \(n-x\)。

那具体怎么求呢?对每个位置求出 \(nxt\) 和 \(pre\) 表示后一个/前一个和它相等的数的所在位置。再对每一种数值求出 \(l,r\) 表示这种数值最左边的数和最右边的数的位置。还有每种数值的出现次数 \(cnt\)。

一个无缝子序列的充要条件是:对于任意 \(x<y\) 且 \(x,y\) 属于无缝子序列,\(r_x<l_y\)。

发现如果 \(r_x<l_y,r_y<l_z\) 则 \(r_x<l_z\)。
那么可以从小到大遍历每种数值,如果当前数值不能再扩张了,就把之前记录下的所有数值共同构成一个无缝子序列,计算其拓展长度并更新最大值。

注意最后输出 \(n\) 减去这个最大值。

最后看在题解写的这么详细的份上,给个关注呗

喜闻乐见的代码:

#include <bits/stdc++.h>

using namespace std;

int n;
int a[1000005];
int b[1000005];

int l[1000005], r[1000005];
int cnt[1000005] = {};
int pos[1000005] = {}, pre[1000005], nxt[1000005] = {};

int cal(int mn, int mx) { //计算最小值为mn最大值为mx 的无缝子序列拓展长度 
	int res = 0;
	for (int i = mn; i <= mx; i++) //先加上子序列内的数个数 
		res += cnt[i];
	for (int i = l[mn - 1]; i && i < l[mn]; i = nxt[i]) //在mn左边的mn-1个数 
		res++;
	for (int i = r[mx + 1]; i > r[mx]; i = pre[i]) //在mx右边的mx+1个数 
		res++;
	return res;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
		b[a[i]] = 1;
	}
	for (int i = 1; i <= 1000000; i++)
		b[i] += b[i - 1];
	for (int i = 1; i <= n; i++)
		a[i] = b[a[i]]; //离散化 
	
	for (int i = 1; i <= n; i++)
		if (l[a[i]] == 0)
			l[a[i]] = i;
	for (int i = n; i >= 1; i--)
		if (r[a[i]] == 0)
			r[a[i]] = i;
	
	for (int i = 1; i <= n; i++) {
		pre[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	memset(pos, 0, sizeof pos);
	for (int i = n; i >= 1; i--) {
		nxt[i] = pos[a[i]];
		pos[a[i]] = i;
	} //求辅助数组们 
		
	int UL = 0;
	for (int i = 1; i <= n; i++) {
		UL = max(UL, a[i]); //求最大值好遍历 
		cnt[a[i]]++;
	}
	
	int lst = 1;
	int ans = 0;
	for (int i = 2; i <= UL + 1; i++)
		if (r[i - 1] > l[i] || i == UL + 1) {
			ans = max(ans, cal(lst, i - 1));
			lst = i;
		}
	printf("%d", n - ans);
	return 0;
}

标签:1000005,P3411,int,题解,mn,序列,mx,无缝
From: https://www.cnblogs.com/FLY-lai/p/18020661

相关文章

  • P5914 MOS 题解
    一道练习贪心证明的好题。绝大多数题解只是点出了以下结论:要么最快的带最慢的;要么最慢的带次慢的。并没有给出证明。我就补上这个证明。为了证明这个贪心结论,我们先证明几个引理。引理一:每次将火把带回来的,一定是对岸最快的。引理一证明:如果回来的不是对岸最快的,让对岸最......
  • JAVA基础-序列化
    1,什么是序列化?Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程。2,序列化的使用场景永久性保存对象,保存对的字节序列到本地文件或者数据库中;通过序列化以字节流的形式对象在网络中进行传递和接收;通过序列化在进程间传递......
  • 递增子序列--连续与不连续
    问题一:最长严格递增子序列的长度题目:给定一个整数数组nums,找到其中最长严格递增子序列的长度。状态定义:dp[i]表示以nums[i]结尾的最长严格递增子序列的长度。状态转移方程对于每个nums[i],遍历其之前的所有元素nums[j](j从0到i-1),如果nums[i]>nums[j],则可以考虑......
  • CF167B题解
    CF167B这里更容易进入且有翻译题意给定初始背包容量\(k\),要进行\(n\)场比赛,每场比赛有\(p_i\%\)的概率能够胜利,赢的一场比赛能获得一个奖励——当\(a_i=-1\)时获得一个体积为\(1\)的奖品,或者当\(a_i>0\)时给背包增加\(a_i\)容量,求所有比赛结束后至少赢得\(......
  • 理想的正方形——题解
    题目描述一看正方形,得,二维数组,单调队列。单调队列可以将一个区间最大值存储,所以只需要根据给定的正方形长度先横着推一遍,再竖着推一遍,将正方形中的最大值和最小值都储存在正方形右下角方格,最后遍历即可。先以行储存以k为长度的最大/小值;再以剩下k-m横向长度的最值向下扩展k个......
  • 跨域问题解决
    跨域举例A网站部署在localhost:63343请求loocalhost:8080/api/user/add,就会出现跨域问题。同源策略同源策略:协议,主机,端口,只有这三者全部相同时,才可以相互访问。现在接口地址为101.10.11.1X:8081,请判断以下哪些可以通过:访问地址描述结果https://127.0.0.1:808......
  • 数列的异或和(题解)
    题目样例样例输入5512345113135036113135样例输出0257二进制运算二进制运算的优先级小于四则运算,所以在与四则运算同时出现时,注意加括号按位与(&)在二进制下,相同位的数都为1时,这一位的结果为1,任意一个不是1或都是0,则为0(eg:0100110&0010111=000......
  • KY22 最大序列和C
    题目例子给的很好,还有不要遗漏全是负数的情况。#include<stdio.h>#include<math.h>intmain(){longlongn=0;while(scanf("%ld",&n)!=EOF){longlongsum=0;longlongmax=0;inttag=0;longlongmaxn=pow(-2,63);......
  • 场景问题解决方法
    1.tomcatspringboot通过域名访问时直接跳到127.0.0.1的问题这种情况极可能是因为 server.xml配置问题导致,可以参考这篇文章tomcat设置http代理详细教程-知乎(zhihu.com)2.如何访问内网中所有的服务和站点要访问一个内网中所有的服务和站点(如内网的所有网站和数据库等),......
  • think-cell Round 1 题解 (A~F)
    think-cellRound1.目录A.MaximiseTheScore排序后输出所有奇数位之和.B.PermutationPrinting\(1,n,2,n-1\cdots\).C.LexicographicallyLargest注意到对于一个\(a_i\)来说\([a_i+1,a_i+i]\)中的所有数都可以被选中,那么问题变给若干区间,每个区间选一个数要......