POJ3320 尺取法的正确使用法

一、前言及题意:

最近一直在找题训练,想要更加系统的补补思维,补补漏洞什么的,以避免被个类似于脑筋急转弯的题目干倒,于是在四处找书,找了红书、蓝书,似乎都有些不尽如人意。这两天看到了日本人的白书,重新读了一遍,其中若干章节写的非常务实也实践起来相当实用,于是这就是白书上面一道推荐的题目,用于训练尺取法的例题。考虑到最近老是读错题,所以就慢慢习惯于首先把个题目翻译成中文之后在进行解读:

杰西卡是个非常可爱的女孩子,因而有若干男孩子追她,最近他的考试要到了,她需要花相当多部分的时间在这件事情上面,吐过他想通过考试,那么她就必须把所有的只是点都熟悉透,但是写教科书的人似乎十分在意一些奇怪的东西,于是他将将有的知道hisIan重复了若干次。杰西卡童鞋希望知道她最少需要看多少页连续的书才能够完成她的复习进度。一个爱慕她的男孩子已经把每一页的知识点使用独立的编号标示了出来,但是他并不能够很好的完成这个统计工作,所以你收到的聘用。

链接:https://vjudge.net/problem/POJ-3320

二、做法:

传统意义上如果我们要枚举连续的片段将会几乎必然花费N2的时间来进行这个枚举,但是根据尺取法的思路,我们并没有必要完全的枚举每种集合(如果他们显然不合理的的话),此时的思路是,首先设置一个游标,使得游标在慢慢往后移动这代表了整个区间的结束位置,没到达一个点,将记录该点在区间中的出现次数,如果之前没有出现过,则应当给CNT变量加上1,如果此时cnt变量等于所有知识点的总数,则应开始移动开始端的游标,每到一处则减少1.。

但是这道题有些坑:
1,及即使关了同步,cin也会因为太慢而超时。

2,因为输入整个只有一行,所以关同步这个操作会使得scanf无法读取到全部所有的数据。

于是注释掉关同步的行,cin换成scanf就可以了。

详见代码:

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
using namespace std;

const long long MAXN=1000000+233;
int arr[MAXN];
int numb[MAXN];
int cntt[MAXN];
int ans=MAXN;
int n;

set<int>s;
void init()
{
    cin>>n;
    int pp=0;
    for(int i=0;i<n;++i)
    {
        scanf("%d",&arr[i]);
//        cin>>arr[i];
        if(!s.count(arr[i]))numb[pp++]=arr[i],s.insert(arr[i]);
    }sort(numb,numb+pp);
    int spos=-1;int cnt=0;
    for(int i=0;i<n;++i)
    {
        int pos=lower_bound(numb,numb+pp,arr[i])-numb;
        if(!cntt[pos])cnt++;cntt[pos]++;
        while(cnt==pp)
        {
            ans=min(ans,i-spos);
            spos++;
            int pos2=lower_bound(numb,numb+pp,arr[spos])-numb;
            cntt[pos2]--;
            if(!cntt[pos2])cnt--;
        }
    }
    cout<<ans<<"\n";

}

int main()
{
//    cin.sync_with_stdio(false);
    init();    

    return 0;
}
时间: 2024-10-03 14:06:42

POJ3320 尺取法的正确使用法的相关文章

poj3320尺取法

Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The author of that

poj3320 (尺取法)

n个数,求最小区间覆盖着n个数中所有的不相同的数字. 解题思路: AC代码: import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Scanner; import java.util.Set; public class Main{ /** * @param args */ static int n; static Set<Integer> set = new Hash

KMP的正确使用法_x新疆网络赛Query on a string

Query on a string 题意,给定一个大字符串,给定一个小模式串,定义 两种不同的任务模式,分别是查询和更改: 查询对应区间内,有多少个匹配到位的数字: 修改某一位的某一个字母. 于是直觉告诉我们是KMP,而且需要一个单点更新,动态查询的数据结构--直觉上认为树状数组比较合适执行这个任务. 于是,开个大大数组,保存每次匹配时对应位的四字母的匹配指针的位置. 每次扫描到了模式串长度都往树状数组里面存入相关元素. 每次修改之后应当从新就地走一遍模式串,更新相关内容,注意,每次匹配到的新的

poj3061 Subsequence&amp;&amp;poj3320 Jessica&#39;s Reading Problem(尺取法)

这两道题都是用的尺取法.尺取法是<挑战程序设计竞赛>里讲的一种常用技巧. 就是O(n)的扫一遍数组,扫完了答案也就出来了,这过程中要求问题具有这样的性质:头指针向前走(s++)以后,尾指针(t)要么不动要么也往前走.满足这种特点的就可以考虑尺取法. poj3061 比较简单,也可以用二分做,时间复杂度O(n*logn).用尺取法可以O(n)解决. #include<iostream> #include<cstdio> #include<cstdlib> #i

尺取法 poj3061 poj3320

尺取法就是反复推进区间的开头和结尾,来求满足条件的最下区间. poj3061 http://poj.org/problem?id=3061 给定一个都是正整数的序列,要我们求总和不小于S的连续子序列的长度的最小值 如果序列   是总和最迟大于S的连续子序列 那么  所以只有加上, 从开始的连续子序列才有可能大于S 所以从开始的总和最初大于S的连续子序列是则一定有 1 #include <stdio.h> 2 #include <string.h> 3 #include <st

poj3320(Jessica&#39;s Reading Problem)尺取法

Description Jessica's a very lovely girl wooed by lots of boys. Recently she has a problem. The final exam is coming, yet she has spent little time on it. If she wants to pass it, she has to master all ideas included in a very thick text book. The au

【尺取法】POJ3061 &amp; POJ3320

POJ3061-Subsequence [题目大意] 给定长度微n的数列整数及整数s.求出总和不小于s的连续子序列的长度的最小值.如果节不存在,则输出0. [思路] 尺取法五分钟裸裸裸~刷水刷出了罪恶感:( 基本做法:设置l和r代表当前区间[l,r],若S(l,r)<s,则 r++.若S(l,r)≥s,则 l++,直至S(l,r)<s.如果当前S(l,r)<s且r=n则退出.输出最小区间长度[l,r]即可. 1 #include<iostream> 2 #include<

【尺取法】【转】

尺取法:顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案.之所以需要掌握这个技巧,是因为尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的 使用尺取法时应清楚以下四点: 1.  什么情况下能使用尺取法?  2.何时推进区间的端点? 3.如何推进区间的端点? 3.何时结束区间的枚举? 尺取法通常适用于选取区间有一定规律,或者说所选取的区间有一定的变化趋势的情况,通俗地说,在对所选取区间进行

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间