非全包含
代码注释与解题思路
解题思路
这道题目要求我们找到一个序列A,通过移除末尾元素的操作,使得序列不再包含1到M的所有整数。我们需要找出最少需要移除多少个末尾元素才能满足这个条件。
关键思路:
- 检查初始状态:首先判断原始序列是否已经不符合条件(即不包含1到M的所有整数)
- 寻找临界点:如果初始符合条件,则找到从后往前第一个使得序列不再包含1到M所有整数的位置
- 计算操作次数:根据找到的临界点计算需要移除的元素数量
代码注释
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e2+5; // 定义常量N为105,足够容纳最大输入规模
int n, m; // n表示序列长度,m表示需要检查的整数范围1-m
int x, vis[N]; // x用于临时存储输入的数字,vis数组标记1-m中哪些数字已经出现过
int main(){
// 输入序列长度n和范围m
cin>>n>>m;
int flag = 0; // flag记录最后一个满足"包含1-m所有数"的位置
for(int i=1;i<=n;i++){
cin>>x; // 读入当前数字
vis[x] = 1; // 标记该数字已出现
// 检查1到m的所有数字是否都已出现
for(int j=1;j<=m;j++){
if(vis[j]==0){
// 如果发现缺失的数字,更新flag为当前位置i
flag = i; // 到第i个数还不满足包含1-m所有数
break;
}
}
}
// 输出结果:总长度n减去最后一个满足条件的位置flag
// 即需要移除n-flag个末尾元素才能使条件不成立
cout<<n-flag;
return 0;
}
代码解析
-
初始化:
- 定义数组
vis
用于记录1到m的数字是否出现过 flag
变量初始化为0,用于记录关键位置
- 定义数组
-
遍历输入序列:
- 逐个读取数字并标记其出现
- 每次读取后检查1到m的所有数字是否都已出现
- 如果发现缺失,则更新
flag
为当前位置
-
计算结果:
n-flag
表示需要移除的末尾元素数量- 如果初始就不满足条件,
flag
等于n,输出0 - 如果全部满足,
flag
为0,需要移除全部n个元素
示例分析
样例1:
输入:
5 3
3 2 3 1 2
处理过程:
- 读取3,vis[3]=1,flag=1
- 读取2,vis[2]=1,flag=2
- 读取3,vis不变,flag=3
- 读取1,vis[1]=1,此时1-3都已出现,flag不更新
- 读取2,vis不变
最终flag=3(位置3时首次满足条件),输出5-3=2
样例2:
输入:
4 3
1 3 1 3
处理过程:
- 读取1,vis[1]=1,flag=1
- 读取3,vis[3]=1,flag=2
- 读取1,vis不变,flag=3
- 读取3,vis不变
始终缺少2,flag保持更新到最后为4,输出4-4=0
该算法高效地通过一次遍历即可确定结果,时间复杂度为O(n*m),在题目约束下完全可行。