http://poj.org/problem?id=2823
给你一组数字,滚动窗口,每次只能看见几个数字,(每次左边出去一个,右边进来一个)求每次的最大数字和最小数字,做了三遍啊啊啊啊。。。。
第一想法比较暴力,判断上一次是不是第一个值是最大的或者最小的,如果是,就重新比较,不是就拿上次的最大值或者最小值和最新加入窗口的值比较。
代码如下(超时) 如果是noj应该可以过23333~~~~
#include <iostream> #include <cstdio> #include <queue> #define maxnum 1000 int curmax,curmin,Max[maxnum],Min[maxnum]; using namespace std; int main() { int n,k; scanf("%d%d",&n,&k); int a[maxnum]; for (int i = 0 ; i < n ; i++) scanf("%d",&a[i]); int i = 0, j = 0,maxn = -maxnum , minn = maxnum; for (int i = 0 ; i < k; i++) { if(a[i] > maxn) { Max[0] = maxn = a[i]; curmax = i; } if(a[i] < minn) { Min[0] = minn = a[i]; curmin = i; } } for ( i = 1 ; i < n-k+1 ; i++) { Max[i] = (curmax == i -1 ) ? -maxnum : Max[i-1]; Min[i] = (curmin == i -1 ) ? maxnum : Min[i-1]; for ( j = (curmax == i -1 ) ? i : i+k-1 ; j < i+k ; j++ ) { if(a[j] > Max[i]) { Max[i] = a[j]; curmax = j; } } for ( j = (curmin == i -1 ) ? i : i+k-1 ; j < i+k ; j++ ) { if(a[j] < Min[i]) { Min[i] = a[j]; curmin = j; } } } for (int i = 0 ; i < n-k+1 ;i++) printf("%d%c",Min[i],(i == n-k )?'\n':' '); for (int i = 0 ; i < n-k+1 ;i++) printf("%d%c",Max[i],(i == n-k )?'\n':' '); return 0; }
比赛的时候就放过去了,没再做。。。后来想到优先队列,不过我写的会超时,有大神的不会。。。。比赛查重到了两个人贴了同一个大神的呵呵呵
我想的是存pair,第一个值是本身数值,第二个是他所在的第一位,这样可以判断他是不是被t出去的那个最左边的值,在复杂度上降了一级,代码如下,但是还是超时了,虽然说优先队列可以做,但是我还没想出来最好的方法,没看别人题解呢。。。
#include <iostream> #include <cstdio> #include <queue> #include <utility> #include <functional> #include <deque> #define maxn 1000005 using namespace std; typedef pair<int, int> Pii; priority_queue<Pii> Max; priority_queue<Pii, deque<Pii>, greater<Pii> > Min; int minVal[maxn], maxVal[maxn], num[maxn]; void print(int *s, int n) { for(int i = 0; i < n; i++) { if(i) printf(" "); printf("%d", s[i]); } printf("\n"); } int main() { #define _PUSH_ Max.push(make_pair(num[i], i));\ Min.push(make_pair(num[i], i)); int n, k; scanf("%d%d", &n, &k); for(int i = 0; i < k - 1; i++) { scanf("%d", num + i); _PUSH_ } for(int i = k - 1; i < n; i++) { scanf("%d", num + i); _PUSH_ while(Max.top().second < i - k + 1) Max.pop(); while(Min.top().second < i - k + 1) Min.pop(); minVal[i - k + 1] = Min.top().first; maxVal[i - k + 1] = Max.top().first; } print(minVal , n - k + 1); print(maxVal, n - k + 1); return 0; }
其实是道线段树的模板题,但是入坑时间短,没实现过,只知道大概思路,线段树分区间上很厉害,不管你要几个数的最大值最小值或者平均值(自己在结构体里加)都可以轻松拿出来。。。建立的核心代码:
struct tree
{
int lp,rp,minvalue,maxvalue;
int getmid()
{
return (lp + rp) / 2;
}
} tree[maxnum * 4];
int num[maxnum]; // 往num里面填数字,构建的树的模型,真正的数字要填进去
void build_tree(int left,int right ,int pos)
{
tree[pos].lp = left;
tree[pos].rp = right;
int mid = tree[pos].getmid();
if(right == left)
{
//left和right现在是一样的,最下层的树叶每个里面区间长度为1
tree[pos].maxvalue = tree[pos].minvalue = num[left]; //只在最下面那层填数字
return;
}
build_tree(left,mid,2*pos); //左子树
build_tree(mid+1,right,pos*2+1) //右子树
//要填进去这个区间的最大值最小值需要先递归到他的下一层,即将区间一分为二
tree[pos].minvalue = min(tree[pos*2].minvalue,tree[pos*2+1].minvalue);
tree[pos].maxvalue = max(tree[pos*2].maxvalue,tree[pos*2+1].maxvalue);
}
注释部分应该蛮清晰的吧...ac代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxnum = 1000010; struct ans { int minans,maxans; } aa[maxnum]; struct tree { int lp,rp,minvalue,maxvalue; int getmid() { return (lp + rp) / 2; } } tree[maxnum * 4]; int num[maxnum]; // 往num里面填数字,构建的树的模型,真正的数字要填进去 void build_tree(int left,int right ,int pos) { tree[pos].lp = left; tree[pos].rp = right; int mid = tree[pos].getmid(); if(right == left) { //left和right现在是一样的,最下层的树叶每个里面区间长度为1 tree[pos].maxvalue = tree[pos].minvalue = num[left]; //只在最下面那层填数字 return; } build_tree(left,mid,2*pos); //左子树 build_tree(mid+1,right,pos*2+1) ;//右子树 //要填进去这个区间的最大值最小值需要先递归到他的下一层,即将区间一分为二 tree[pos].minvalue = min(tree[pos*2].minvalue,tree[pos*2+1].minvalue); tree[pos].maxvalue = max(tree[pos*2].maxvalue,tree[pos*2+1].maxvalue); } int query(int lp,int rp,int pos,int id) { if(tree[pos].lp == lp && tree[pos].rp == rp) { if(id == 0) return tree[pos].minvalue; else return tree[pos].maxvalue; } int mid = tree[pos].getmid(); if(mid >= rp) return query(lp,rp,pos*2,id); else if(mid < lp) return query(lp,rp,pos*2+1,id); else { if(id == 0) return min(query(lp,mid,pos*2,id),query(mid+1,rp,pos*2+1,id)); else return max(query(lp,mid,pos*2,id),query(mid+1,rp,pos*2+1,id)); } } int main() { int n,m; while(scanf("%d%d",&n,&m) != EOF) { for(int i = 1; i <= n; ++i) scanf("%d",&num[i]); build_tree(1,n,1); for(int i = 1; i <= n - m + 1; ++i) { int j = i + m - 1; aa[i].minans = query(i,j,1,0); aa[i].maxans = query(i,j,1,1); } for(int i = 1; i <= n - m + 1; i++) printf("%d%c",aa[i].minans,(i == n - m + 1) ? '\n':' '); for(int i = 1; i <= n - m + 1; i++) printf("%d%c",aa[i].maxans,(i == n - m + 1) ? '\n':' '); } return 0; }