这一题,是简单的取尺法的应用。
题目大概的意思是:一个人复习一本书,这本书的每一页都有一个知识点ai,每一页的知识点可能会与其他页的知识点相同,问你如何读最少页,将所以知识点读完。
使用STL中的 set 来判断里面有多少个不同的知识点num, 用STL中的 map 表示知识点与出现次数的映射。
同样的设置知识点数sum,页数的起点和终点s和t。首先将知识点的数组a 加入map中,直到sum >= num,更新需要看多少页,去掉开头那一页,判断知识点是否少了,少了,则 t 再自增,继续加入,否则,再去掉开头那页。不断循环,更新需要看的最少页数。
下面是AC代码:
#include <iostream>
#include <cstdio>
#include <map>
#include <set>
using namespace std;
int n;
int a[1000005];
int min(int x, int y)
{
return x > y ? y : x;
}
void solve()
{
set<int>count;
for(int i = 0; i < n; i++) //数有几个不同的知识点
count.insert(a[i]);
int num = count.size();
map<int, int>finds; //知识点与出现次数的映射
int s, t, sum;
s = t = sum = 0; //起始页与末尾页,知识点数的初始化
int res = n;
while(1)
{
while(t < n && sum < num)
if(finds[a[t++]]++ == 0) //出现新的知识点
sum++; //增加知识点数
if(sum < num) //知识点数少于总的,则可以退出循环了,到尽头了
break;
res = min(res, t - s); //计算页数
if(--finds[a[s++]] == 0) //去掉起始页,判去掉该知识点,该知识点的次数是否为0,是,则知识点数 - 1
sum--;
}
printf("%d\n", res);
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
solve();
return 0;
}