刷刷水题

uva11572
这题有坑。。。
输入一个长度为n的序列A,找一个长度尽量长的连续子序列AL ~ AR, 使得该序列中没有相同的元素。
我们可以滑动窗口,每次left 往右移动一次或者 right往右移动一格,判断a[right]是否在窗口中即可。判断是否在窗口中可以用set。这样整个程序的复杂度是O(n * log n)

/*
 *
 *  Author : Triose
 *  Email  : Triose@163.com
 *  Update_time : 2016.9.11
 *
 */


//#include<bits/stdc++.h>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <math.h>
#include <time.h>
#include <bitset>
#include <iomanip>
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <string.h>
#include <iterator>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define READFILE

#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)

#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define ECH(it, A) for (typeof(A.begin()) it=A.begin(); it != A.end(); ++it)

#define PR(a,b) pair<a,b>
#define slen(str) strlen(str)
#define ds(t) int t; sf(t)
#define Down(t) while(t--)
#define dc(t) int t; cin >> t;
#define dsD(t) ds(t); Down(t)
#define dcD(t) dc(t); Down(t)
#define ALL(A) A.begin(), A.end()
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scpy(str1, str2) strcpy(str1, str2)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define mem(a,b) memset((a),b,sizeof(a))

#define fi first
#define se second
#define LL long long
#define DB double
#define isws ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double E = exp(1.0);

template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
/*******************************头文件到此结束******************************/



int n, m;
vector<int> a;
set<int> exist;

void Init() {
    exist.clear(); a.clear();
    sf(n);
    rep(i, 0, n) sf(m), a.push_back(m);
}

int solve() {
    if(!n) return 0;//可能为0
    int max_len = 1;
    int i = 0, j = 1;
    exist.insert(a[i]);
    while(j < n) {
        if(!exist.count(a[j])) {
            max_len = Max(max_len, j - i + 1);
            exist.insert(a[j++]);
        } else {
            exist.erase(a[i++]);
        }
        if(i == j) exist.insert(a[j++]);            //当 i == j, 记得把a[j]放入,并且j++
    }
    return max_len;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    dsD(t) {
        Init();
        pf(solve());
    }
    return 0;
}

由上一题引出了滑动窗口的最小值问题,描述如下:
输入一个正整数k和长度为n的整数序列A1, A2, A3….An, 定义f[i]为从元素i开始的连续k个元素中的最小值。输出f[1] ~ f[n - k + 1]
最简单的办法,对于每一个i,遍历从i开始的k个数,找到最小值更新。这样一来复杂度会是O((n - k) * k),要我出题肯定卡这个。

那么我们想办法优化一下。(n - k)反正没得优化了,看看这个k有没有办法。
可以考虑先求出f[1],把f[1] ~ f[1 + k - 1]放入一个multiset s中形成一个窗口。接下来就是这么一个过程,i 从 2 ~ n - k - 1, 每次擦除a[i - 1], 放入a[i + k - 1]形成了属于a[i]的窗口,并且multiset 是有序容器(由小到大排列),(s.begin())就是窗口中的最小值。移除的时候考虑到可能窗口里存在多个相同值,所以需要一个迭代器数组维护a[i]在集合中的地址。这样一来时间复杂度就优化到了O((n - k) log k) (毕竟滑动窗口是(n - k)而插入删除是O(log k))。

既然说到了数据结构能在不改变主算法的前提下提高程序效率,考虑是否有更加优化的数据结构。

有的,单调队列。
考虑到一个事实,假设现在窗口覆盖了4个元素分别是: 5 9 11 2(从左到右), 那么在2之前的5 9 11,在移出窗口前永远都不会成为最小值,那么它们就是无用的。窗口的数据结构理论上可以只存2这一个数字。那么我们可以构造这么一种数据结构(单调队列):(满足以下三个条件)
1、队首必须是整个队列中最小的元素。
2、新添加的值放入队尾。
3、若队首元素的值比队尾大,pop掉
这样的数据结构可以用STL实现,在deque的基础上实现。这里不细数。

qnmdCSDN,写一篇博客崩了2次还没有自动保存,你搞毛线啊!
我不写详解了,uva 1471贴代码了:

/*
 *
 *  Author : Triose
 *  Email  : Triose@163.com
 *  Update_time : 2016.9.11
 *
 */


//#include<bits/stdc++.h>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <math.h>
#include <time.h>
#include <bitset>
#include <iomanip>
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <string.h>
#include <iterator>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define READFILE

#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)

#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define ECH(it, A) for (typeof(A.begin()) it=A.begin(); it != A.end(); ++it)

#define PR(a,b) pair<a,b>
#define slen(str) strlen(str)
#define ds(t) int t; sf(t)
#define Down(t) while(t--)
#define dc(t) int t; cin >> t;
#define dsD(t) ds(t); Down(t)
#define dcD(t) dc(t); Down(t)
#define ALL(A) A.begin(), A.end()
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scpy(str1, str2) strcpy(str1, str2)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define mem(a,b) memset((a),b,sizeof(a))

#define fi first
#define se second
#define LL long long
#define DB double
#define isws ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double E = exp(1.0);

template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
/*******************************???????******************************/



int n, m;
const int maxn = 200010;

struct Node {
    int value, f, g;
    Node(int v = 0, int f_ = 0, int g_ = 0):value(v), f(f_), g(g_){}
    friend bool operator < (Node a, Node b) { return a.value < b.value; }
};
Node a[maxn];


void Init() {
    sf(n);
    rep(i, 0, n) sf(a[i].value), a[i].f = a[i].g = 1;
    rep(i, 1, n) if(a[i].value > a[i - 1].value)
        a[i].g = a[i - 1].g + 1;
    per(i, n - 2, 0) if(a[i].value < a[i + 1].value)
        a[i].f = a[i + 1].f + 1;
}

set<Node> s;
set<Node>::iterator fd;

int solve() {
    int maxlen = 1;
    s.clear(); s.insert(a[0]);
    rep(i, 1, n) {
        fd = s.lower_bound(a[i]);
        bool keep = true;
        if(fd != s.begin()) {
            fd--;
            maxlen = Max(maxlen, fd->g + a[i].f);
            if(fd->g >= a[i].g) keep = false;
        }

        if(keep) {
            s.erase(a[i]);
            s.insert(a[i]);
            fd = s.find(a[i]);
            fd++;
            while(fd != s.end() && fd->g <= a[i].g && fd->value > a[i].value) s.erase(fd++);
        }
//      if(fd != s.begin()) fd--;
//      maxlen = Max(maxlen, fd->g + a[i].f);
//      if(fd->g < a[i].g) {
//          s.erase(a[i]); s.insert(a[i]);
//          fd = s.find(a[i]); fd++;
//          while(fd != s.end() && fd->g <= a[i].g && fd->value > a[i].value) s.erase(fd++);
//      }

    }
    return maxlen;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("out.txt", "w", stdout);
#endif
    dsD(t) {
        Init();
        pf(solve());
    }
    return 0;
}

趁还没崩,赶快退出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值