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;
}
趁还没崩,赶快退出