NC20863 数糖纸(桶排序)
数糖纸
https://ac.nowcoder.com/acm/problem/20863
题目
可能很多人要吐槽为什么标题不是“救救blabla”了。
怪人PM6喜欢数糖纸,不同的糖纸有不同的颜色,一共有 N 张糖纸,第 i 张糖纸颜色为 Ci ,它们的位置都是固定的。PM6喜欢五彩缤纷的糖纸,所以他不希望有重复的颜色。他有一次机会,可以收集任意一段连续区间内的糖纸。求出PM6最多能收集多少张糖纸。
输入描述
第一行一个正整数 N ,表示共有 N 张糖纸。
第二行共有 N 个正整数,第 i 个正整数表示第 i 张糖纸的颜色 Ci
对于20%的数据:1<=N<=100
对于40%的数据:1<=N<=1000
对于100%的数据:1<=N<=1e6,0<=Ci<=1e9
输出描述
一个整数表示PM6最多能收集多少张糖纸。
题目分析
1.桶排序的基础想法,可参考 本篇博客
2.题意可直观的理解为,遍历数组一次,找到其中数字不重复的最长区间,
但考虑到 0<=Ci<=1e9 ,如果开辟一个长度为1e9的数组作,似乎不太合理的,
可考虑将其进行离散化,来缩小需开辟数组的长度。
for (int i = 1;i <= n;i ++){ cin >> a[i]; b[i] = a[i]; } sort(b + 1,b + n + 1); int len = unique(b + 1,b + n + 1) - b - 1; ///离散化 for (int i = 1;i <= n;i ++){ //离散化后a[i]中存放的是,原a[i]的值在排序后b[i]中的位置 a[i] = lower_bound(b + 1, b + len + 1,a[i]) - b; }
3.离散化后,从原来判断某个数是否重复出现,变为判断某个数排序后的位置是否重复出现,
这里通过一个 vis 数组来维护病判断是否重复出现。
4.AC代码
#include <bits/stdc++.h> using namespace std; #define long long LL const int maxn = 1e6 + 5; int a[maxn] , b[maxn]; int vis[maxn]; int n; int main(){ while (~scanf("%d",&n)){ for (int i = 1;i <= n;i ++){ cin >> a[i]; b[i] = a[i]; } sort(b + 1,b + n + 1); int len = unique(b + 1,b + n + 1) - b - 1; ///离散化的目的:由于题目中给出的ci的值是1e9,开辟这么大的数组需要很大的空间 for (int i = 1;i <= n;i ++){ a[i] = lower_bound(b + 1, b + len + 1,a[i]) - b;///离散化 } for (int i = 0;i <= len ;i ++) vis[i] = 0; int l = 1,r = 1; int ans = 0; while (l <= r && r <= n){ while (!vis[a[r]] && r <= n){ vis[a[r]] = 1; r ++; } ans = max(ans,r - l); //这里需要注意,因为舒适重复的,获取区间长度后,需要将其遍历过的归零 while (vis[a[r]]){ vis[a[l ++]] = 0; } } cout << ans << endl; } return 0; }