poj 3320(尺取法)

时间:2021-07-04 02:39:15

传送门:Problem 3320

参考资料:

  [1]:挑战程序设计竞赛

题意:

  一本书有 P 页,每页都有个知识点a[i],知识点可能重复,求包含所有知识点的最少的页数。

题解:

  相关说明:

    设以a[start]开始的最初包含所有知识点的最少连续子序列为a[start,....,end];

    mymap[ a[i] ] : 知识点 a[i] 在当前最少连续子序列中出现的次数。

  (1):求出所需复习的知识点总个数。

  (2):求出最先包含所有知识点的最少页数a[start,........,end]。

  (3):end++,mymap[ a[end] ]++,并判断mymap[ a[start] ]是否大于1,如果大于,start++,直到不大于为止,并更新 res。

  (4):重复(3)过程,直到end > P。

AC代码:

 #include<iostream>
#include<cstdio>
#include<set>
#include<map>
using namespace std;
const int maxn=1e6+; int P;
int idea[maxn];
set<int>myset;
map<int ,int >mymap; int Solve()
{
int sumIdea=myset.size();//步骤(1)
int start=,end=;
while(sumIdea != )//步骤(2)
{
sumIdea -= (mymap[idea[end]] == ? :);
mymap[idea[end++]]++;
while(mymap[idea[start]] > )
mymap[idea[start++]]--;
}
int res=end-start;
while(end <= P)//重复执行步骤(3)(4)
{
mymap[idea[end++]]++;
while(mymap[idea[start]] > )
mymap[idea[start++]]--;
res=min(res,end-start);
}
return res;
} int main()
{
scanf("%d",&P);
for(int i=;i <= P;++i)
{
scanf("%d",idea+i);
myset.insert(idea[i]);//set去重
mymap[idea[i]]=;
}
printf("%d\n",Solve());
}
 #include<iostream>
#include<cstdio>
#include<set>
#include<map>
using namespace std;
const int maxn=1e6+; int P;
int idea[maxn];
set<int>myset;
map<int ,int >mymap; int Solve()
{
int sumIdea=myset.size();
int start=,end=;
int total=;
int res=;
while()
{
while(end <= P && total < sumIdea)
total += ((mymap[idea[end++]]++) == ? :); if(total < sumIdea)//如果 total < sumIdea,说明跳出上一个while()的条件为 end > P
break;
res=(res == || res > end-start ? end-start:res);
if(--mymap[idea[start++]] == )
total--;
}
return res;
} int main()
{
scanf("%d",&P);
for(int i=;i <= P;++i)
{
scanf("%d",idea+i);
myset.insert(idea[i]);//set去重
mymap[idea[i]]=;
}
printf("%d\n",Solve());
}

挑战程序设计竞赛