【题解】P1638 逛画展-C++

原题传送门

思路
这道题目可以通过尺取法来完成 (我才不管什么必须用队列)
什么是尺取法呢?
顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。
之所以需要掌握这个技巧,是因为尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以尺取法是一种高效的枚举区间的方法,一般用于求取有一定限制的区间个数或最短的区间等等。当然任何技巧都存在其不足的地方,有些情况下尺取法不可行,无法得出正确答案。

首先这是尺取法的板子题,我们假设从第s幅画开始看,为了覆盖所有大师的画需要看到t。这样的话可以知道如果从s+1开始看的话,那么必须看到t>=t幅画为止。so,我们从区间的最开头把s取出之后,s这幅画所属的大师出现次数就要减1,如果此时这个大师出现次数为0了,在同一个大师再次出现之前,不停将区间末尾t向后推进即可。每次在区间末尾追加画t时将t所属的大师出现次数加1,这样就完成了下一个区间上各个大师出现次数的更新,重复这一操作便能在O(nlogn)的时间复杂度下解决这道题。
代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int p[1000010],k[2019];
 4 set<int> s;int n,m;
 5 int main()
 6 {
 7     cin>>n>>m;
 8     int l=1,r=n,cnt=0,left=1,right=n;
 9     for(int i=1;i<=n;i++)
10     {
11         cin>>p[i];
12         k[p[i]]++;
13         if(!s.count(p[i]))cnt++;
14         s.insert(p[i]);
15         if(cnt==m)
16         {
17             r=i;
18             while(k[p[l]]>1)
19             {
20                 k[p[l]]--;
21                 l++;
22             }
23             if(r-l<right-left)left=l,right=r;
24         }
25     }
26     cout<<left<<" "<<right<<endl;
27     return 0;
28  } 

 

posted @ 2019-07-19 15:22  摸鱼酱  阅读(469)  评论(0编辑  收藏  举报