https://www.lanqiao.cn/problems/3199/learning/?isWithAnswer=true&page=1&first_category_id=1&name=%E5%B0%8F%E6%98%8E%E5%92%8C%E5%AE%8C%E7%BE%8E%E5%BA%8F%E5%88%97
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int a[N];
int main()
{
int n,i,sum=1,ans=0;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+n+1);
a[n+1]=-1;//多加一个使原来最后一个能算进去
for(i=1;i<=n;i++)
{
if(a[i]==a[i+1])
{
sum++;
}
else
{
if(sum>a[i])
ans+=sum-a[i];
if(sum<a[i])
ans+=sum;
sum=1;
}
}
cout<<ans;
return 0;
}
这个代码的思路是统计数组中相同数字出现的次数,并且确保这个次数与数字的值相匹配,这样才能形成"完美序列"。若次数与数字的值不匹配,则计算出需要删除的元素数量,以使剩余的序列变为完美序列。下面是这个过程的详细步骤:
n
并从标准输入读取n
个整数到数组a
中。a
进行排序,这样相同的数字会排列到一起,方便统计。a[n+1]
设置为-1,这是一种技巧,用来标记数组的末尾,以便最后一个数字能够被正确处理。sum
为1,sum
用来统计当前数字连续出现的次数。a
,在每个步骤中:
a[i]
等于下一个数字a[i+1]
,则sum
加1。a[i]
不等于下一个数字a[i+1]
(或者已经是最后一个数字),则比较sum
和a[i]
:
sum
大于a[i]
,表示有多余的数字,需要删除sum
- a[i]
个数字。sum
小于a[i]
,表示数字不够,需要删除所有这些数字。sum
重置为1,以便统计下一个数字。ans
累加了所有需要删除的元素数量。ans
,即为最少需要删除的数字个数,以形成完美序列。整个代码的关键在于对数组排序后方便统计每个数字出现的次数,并通过比较每个数字的值和其出现次数来确定删除元素的数量。
在实际使用中,这个代码是有效的,只要保证输入的数字个数n
加上1不超过数组a
定义的大小N
(这里是100005)。这个假设是安全的,因为a[n+1]
是代码中人为设置的一个哨兵值,用于处理最后一个数字。由于-1
不可能出现在输入的数字序列中,所以它提供了一个可靠的终止处理的标记。