子序列 NYOJ (尺取法+队列+hash) (尺取法+离散化)

子序列

时间限制:3000 ms  |  内存限制:65535 KB

难度:5

描述

给定一个序列,请你求出该序列的一个连续的子序列,使原串中出现的所有元素皆在该子序列中出现过至少1次。

如2 8 8 8 1 1,所求子串就是2 8 8 8 1。

输入
第一行输入一个整数T(0<T<=5)表示测试数据的组数
每组测试数据的第一行是一个整数N(1<=N<=1000000),表示给定序列的长度。
随后的一行有N个正整数,表示给定的序列中的所有元素。
数据保证输入的整数都不会超出32位整数的范围。
输出
对于每组输入,输出包含该序列中所有元素的最短子序列的长度
样例输入
2
5
1 8 8 8 1
6
2 8 8 8 1 1
样例输出
2
5
来源
POJ月赛改编

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<queue>
#include<deque>
#include<iomanip>
#include<vector>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<fstream>
#include<memory>
#include<list>
#include<string>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define MAXN 1000044
#define INF 1000000009
#define eps 0.00000001
/*
利用队列从前到后遍历数组元素
当前元素未在之前出现过,更新ans为队列元素个数
当前元素在之前出现过
    如果当前队首元素在hash表中出现次数多于1次,pop
*/
int T, n, aim, a[MAXN],b[MAXN];
typedef struct Hashnode
{
    int data;
    int cnt;
    struct Hashnode* next;
}*List;
typedef struct Hashtb
{
    List* L;
}*HashTable;
HashTable Init()
{
    HashTable H = (HashTable)malloc(sizeof(Hashtb));
    H->L = (List*)malloc(sizeof(List)*MAXN);
    for (int i = 0; i < MAXN; i++)
    {
        H->L[i] = (List)malloc(sizeof(Hashnode));
        H->L[i]->data = 0;
        H->L[i]->cnt = 0;
        H->L[i]->next = NULL;
    }
    return H;
}
int Hash(int x)
{
    return x%MAXN;
}
void clear(HashTable H)
{
    for (int i = 0; i < MAXN; i++)
    {
        H->L[i]->data = 0;
        H->L[i]->cnt = 0;
        H->L[i]->next = NULL;
    }
}
List find(int x, HashTable H)
{
    List l = H->L[Hash(x)];
    List p = l->next;
    while (p != NULL&&p->data != x)
        p = p->next;
    return p;
}
int cnt(int x, HashTable H)
{
    List p = find(x, H);
    if (p == NULL)
        return -1;
    else
    {
        if (p->cnt > 1)
        {
            p->cnt--;
            return p->cnt + 1;
        }
        else
            return p->cnt;
    }
}
bool Insert(int x, HashTable H)
{
    List l = H->L[Hash(x)];
    List p = find(x, H);
    if (!p)
    {
        List tmp = (List)malloc(sizeof(Hashnode));
        tmp->data = x;
        tmp->cnt = 1;
        tmp->next = l->next;
        l->next = tmp;
        return false;
    }
    else
    {
        p->cnt++;
        return true;
    }
}
int main()
{
    scanf("%d", &T);
    HashTable H = Init();
    while (T--)
    {
        clear(H);
        scanf("%d", &n);
        int ans = INF,tmp;
        queue<int> q;
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &tmp);
            if (!Insert(tmp,H))
            {
                q.push(tmp);
                ans = q.size();
            }
            else
            {
                q.push(tmp);
                while (!q.empty()&&cnt(q.front(),H) > 1)
                {
                    q.pop();
                }
                ans = min(ans,(int)q.size());
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

时间: 2024-11-08 04:34:44

子序列 NYOJ (尺取法+队列+hash) (尺取法+离散化)的相关文章

poj 3320 Jessica&#39;s Reading Problem(尺取法+map/hash)

题目:http://poj.org/problem?id=3320 题意:给定N个元素的数组,找出最短的一段区间使得区间里面的元素种类等于整个数组的元素种类. 分析:暴力枚举区间的起点x,然后找到最小的y,使得区间[x,y]满足条件,x向有移位后变成x',现在的y'肯定不至于在y的左边.存状态的话map和hash都可以. map代码: #include <iostream> #include <set> #include <map> #include <cstdi

POJ 3320 尺取法,Hash,map标记

1.POJ 3320 2.链接:http://poj.org/problem?id=3320 3.总结:尺取法,Hash,map标记 看书复习,p页书,一页有一个知识点,连续看求最少多少页看完所有知识点 必须说,STL够屌.. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio>

最美丽的花--百变魔尺-24段魔尺玩法

最美丽的花--百变魔尺-24段魔尺玩法

近期目标:单调队列,尺取,分块,块状链表

近期打算赶紧补一些遗漏的知识点 尺取:https://blog.csdn.net/consciousman/article/details/52348439 单调队列: https://blog.csdn.net/justmeh/article/details/5844650  https://blog.csdn.net/Hackbuteer1/article/details/7424466 数列分块入门:hwzer数列分块入门 块状链表:https://blog.csdn.net/wypblo

bzoj 2124 等差子序列 树状数组维护hash+回文串

等差子序列 Time Limit: 3 Sec  Memory Limit: 259 MBSubmit: 1919  Solved: 713[Submit][Status][Discuss] Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数. 下接T组数据,

最大子序列和(单调队列算法)

题目大意: 给定一个长度为N的序列,请你求出它最大长度不超过M的最大子序列的和(其中 N,M<=3*10^5) 分析: 一般对于这样的题目,我们最现实想到的就是前缀和,通过枚举序列可以得到答案,但这样的时间复杂度显然是不乐观的(TLE) 所以我们可以通过队列来优化  (这个算法我们称之为单调队列算法) 我们先枚举子序列的有端点 i 此时问题转变为寻找一个 j 最为子序列的左端点 (i-m <= j <= i-1),使得是S[ j ] 最小 (S数组表示前缀和) 这时我们不妨再设一个 k

CF452F Permutations/Luogu2757 等差子序列 树状数组、Hash

传送门--Luogu 传送门--Codeforces 这种题目还能跟哈希扯上关系也是很神了-- 如果存在长度\(>3\)的等差子序列,那么一定存在长度\(=3\)的等差子序列,所以我们只需要找长度为\(3\)的等差子序列.可以枚举等差子序列的第二个元素\(b\),那么存在长度为\(3\)的等差子序列等价于:可以在\(b\)左边找到一个元素\(a\),在\(b\)右边找到一个元素\(c\),满足\(b - a = c - b\). 对于找到\(ac\)两个元素,一个比较直观的想法是:对\(b\)左

bzoj2124 等差子序列(树状数组+hash)

题意 给你一个1~n排列,问有没有一个等差数列(长度至少为3) 题解 我居然自己想到了正解. 但我最后写挂了,所以我又看了题解. 我们维护了一个以权值为下标的01序列. 我们扫描整个序列.对于每一个正在扫描的数,我们判断以这个数的权值作为对称点,01序列是否对称. 这个序列用权值树状数组维护就行. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #

POJ3162 Walking Race(树形DP+尺取法+单调队列)

题目大概是给一棵n个结点边带权的树,记结点i到其他结点最远距离为d[i],问d数组构成的这个序列中满足其中最大值与最小值的差不超过m的连续子序列最长是多长. 各个结点到其他结点的最远距离可以用树形DP解决,HDU2196. 而那个最长的连续子序列可以用单调队列求..搞了挺久看了解法体会了下..简单来说就是尺取法,用两个指针[i,j]表示区间,j不停+1往前移动,然后用两个单调队列分别同时更新区间最小值和最大值,再看两个队列队首的最值差是否大于m,是的话出队并调整i值,最后用j-i+1更新答案.