nyoj133 子序列 哈希+队列

来源:互联网 发布:红黑树 c语言实现 编辑:程序博客网 时间:2024/05/17 02:45
描述

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

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

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

题目简单,实际很坑,考虑不完整就错,思路就是从每次记录每个数字的出现次数,由于范围是2^32,所以用哈希存,注意哈希 每个样例清零的时候,delete后,指针不会变为NULL要手动赋值,这点坑了太久,哎,基础功不扎实,然后注意队首的hash(front)>1时,考虑弹出,注意坑的地方在你不能从左到右扫到第一个后面没有的值,再从右到左扫到前面没有出现的值,这样不是最优解,比如考虑1,2,3,4,4,1,2,4,2,3,这样得到答案为5,错误,代码如下:

#include<queue>#include<cstdio>#include<cmath>#include<iostream>using namespace std;const int M=1000001;int inf=1<<28;struct node{node *next;int num;int x;node(){next=NULL;}node(int a){x=a;num=1;next=NULL;}};node no[M];void del(node * h){if (h==NULL) return;del(h->next);delete h;}int t;int hash_size;bool hash1(int x){t=x%M;node *p=no[t].next;while(p){if (p->x ==x){p->num++;return 1;}else p=p->next;}p=new node(x);p->next=no[t].next;no[t].next=p;hash_size++;return 0;}bool hash2(int x){node *p=no[x%M].next;while(p){if (p->x==x){if (p->num>=2){p->num--;return 1;}else return 0; }else p=p->next;}return 0;}int main(){int T,n,ans;int x;bool f;scanf("%d",&T);getchar();while(T--){for (int i=0;i<M;i++) {del(no[i].next);no[i].next=NULL;//手动赋值为NULL }scanf("%d",&n);queue<int> q;ans=inf;hash_size=0;for (int i=0;i<n;i++){scanf("%d",&x);if (q.empty()) {q.push(x);no[x%M].next=new node(x);ans=1;hash_size++;}else {f=hash1(x);if (f){q.push(x);t=q.front();while(hash2(t)){q.pop();t=q.front();}ans= min(ans,(int)q.size());//十分重要!!!巨坑 }else {q.push(x);ans=q.size();//有新的元素之间赋值}}}printf("%d\n",ans);}} 




0 0