p1440(RMQ入门)求区间的最小值(没想象中那么简单)

补:这个题正确做法好像是单调队列??我真的不知道,我瞄了一眼就直接结论区间题。然后敲了RMQ

先放上RMQ模板代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
const int MAXN = 100117;
int n,query;
int num[MAXN];
 
int F_Min[MAXN][20],F_Max[MAXN][20];
 
void Init()
{
    for(int i = 1; i <= n; i++)
    {
        F_Min[i][0] = F_Max[i][0] = num[i];
    }
 
    for(int i = 1; (1<<i) <= n; i++)  //按区间长度递增顺序递推
    {
        for(int j = 1; j+(1<<i)-1 <= n; j++)  //区间起点
        {
            F_Max[j][i] = max(F_Max[j][i-1],F_Max[j+(1<<(i-1))][i-1]);
            F_Min[j][i] = min(F_Min[j][i-1],F_Min[j+(1<<(i-1))][i-1]);
        }
    }
}
 
int Query_max(int l,int r)
{
    int k = (int)(log(double(r-l+1))/log((double)2));
    return max(F_Max[l][k], F_Max[r-(1<<k)+1][k]);
}
 
int Query_min(int l,int r)
{
    int k = (int)(log(double(r-l+1))/log((double)2));
    return min(F_Min[l][k], F_Min[r-(1<<k)+1][k]);
}
 
int main()
{
    int a,b;
    scanf("%d %d",&n,&query);
    for(int i = 1; i <= n; i++)
        scanf("%d",&num[i]);
    Init();
    while(query--)
    {
        scanf("%d %d",&a,&b);
        printf("区间%d到%d的最大值为:%d\n",a,b,Query_max(a,b));
        printf("区间%d到%d的最小值为:%d\n",a,b,Query_min(a,b));
        printf("区间%d到%d的最大值和最小值只差为:%d\n",a,b,Query_max(a,b)-Query_min(a,b));
    }
    return 0;
}

题目描述

一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。

输入输出格式

输入格式:

第一行两个数n,m。

第二行,n个正整数,为所给定的数列。

输出格式:

n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值。

输入输出样例

输入样例#1: 复制

6 2
7 8 1 4 3 2

输出样例#1: 复制

0
7
7
1
1
3 

说明

【数据规模】

m≤n≤2000000

以下做法只能得80,具体原因不知(MEL??这是什么错?没见过)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
int num[maxn];
int dp[maxn][20];
int n,m;
void init()
{
	for(int i=1;i<=n;i++) dp[i][0]=num[i];
	for(int j=1;(1<<j)<=n;j++)
	for(int i=1;i+(1<<j)-1<=n;i++)
		dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int qu(int l,int r)
{
	int k=(int)(log(1.0*(r-l+1))/log(2.0));
	return min(dp[l][k],dp[r-(1<<k)+1][k]);
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&num[i]);
	init();
	for(int i=1;i<=n;i++)
	{
		if(i==1) 
		{
			printf("0\n");
			continue;
		}
		else if(i==2) 
		{
			printf("%d\n",num[1]);
			continue;
		}
		if(i-m<=0) printf("%d\n",qu(1,i-1));
		else printf("%d\n",qu(i-m,i-1));
	}
	return 0;
}

拿出我最擅长的线段树去写,90,最后一个数据超时。。。。。,,具体原因不详

#include<cstdio>
#include<cstring>
#include<algorithm> 
using namespace std;
const int maxn=2e6+10;
int mx[maxn*4],num[maxn];
void build(int l,int r,int id)
{
	if(l==r) 
	{
		int x;
		scanf("%d",&x);
		mx[id]=x;
		num[l]=x;
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
	mx[id]=min(mx[id<<1],mx[id<<1|1]);
}
int qu(int l,int r,int ql,int qr,int id)
{
	if(ql<=l&&r<=qr) return mx[id];
	int mid=(l+r)>>1;
	int ans=0x3f3f3f3f;
	if(ql<=mid) ans=min(ans,qu(l,mid,ql,qr,id<<1));
	if(qr>mid) ans=min(ans,qu(mid+1,r,ql,qr,id<<1|1));
	return ans;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,n,1);
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			printf("0\n");
			continue;
		}
		else	if(i==2)
		{
			printf("%d\n",num[1]);
			continue;
		}
		if(i-m<=0) printf("%d\n",qu(1,n,1,i-1,1));
		else printf("%d\n",qu(1,n,i-m,i-1,1));
	}
}

然后我在线段树上稍微优化了一下,就过了?数据只能说有点水哈(才几个数据)

#include<cstdio>
#include<cstring>
#include<algorithm> 
using namespace std;
const int maxn=2e6+10;
int mx[maxn*4],num[maxn];
void build(int l,int r,int id)
{
	if(l==r) 
	{
		int x;
		scanf("%d",&x);
		mx[id]=x;
		num[l]=x;
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
	mx[id]=min(mx[id<<1],mx[id<<1|1]);
}
int qu(int l,int r,int ql,int qr,int id)
{
	if(ql<=l&&r<=qr) return mx[id];
	int mid=(l+r)>>1;
	int ans=0x3f3f3f3f;
	if(ql<=mid) ans=min(ans,qu(l,mid,ql,qr,id<<1));
	if(qr>mid) ans=min(ans,qu(mid+1,r,ql,qr,id<<1|1));
	return ans;
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	build(1,n,1);
	int mi=qu(1,n,1,n,1);
	int ii;
	for(int i=1;i<=n;i++) 
	if(num[i]==mi) 
	{
		ii=i;
	}
	for(int i=1;i<=n;i++)
	{
		if(i==1)
		{
			printf("0\n");
			continue;
		}
		else	if(i==2)
		{
			printf("%d\n",num[1]);
			continue;
		}
		if(i-m<=0) 
		{
			if(1<=ii&&ii<=i-1) printf("%d\n",mi);
			else	printf("%d\n",qu(1,n,1,i-1,1));
		}
		else 
		{
			if(i-m<=ii&&ii<=i-1) printf("%d\n",mi);
			else	printf("%d\n",qu(1,n,i-m,i-1,1));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/86537288
今日推荐