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;
}