补:这个题正确做法好像是单调队列??我真的不知道,我瞄了一眼就直接结论区间题。然后敲了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));
}
}
}