HDU - 5875 Function (区间取模 RMQ)

题意:

给你n个数和m个查询,然后问你从查询的左端点到右端点依次取模得到的值是多少?

思路: 根据取模的性质,我们可以知道有些数是不用取模的,那么我们主要做的就是如和找到比当前数小的第一个数的位置在哪了,我在网上看到的代码有 就是预处理出比他小的当前的第一个数,时间复杂度大概是 n方,,但是可以过。,这题的正解应该是RMQ预处理出区间最小值,之后二分区间找到第一个比他大的数,时间复杂度是 n*logn*logn。

(还有这套题的输入输出格式真是尼玛丧心病狂,第一次看见有这个 多组输入t组的输入格式)

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#define mes(a) memset(a,0,sizeof(a))
using namespace std;
const int maxn = 110000;
int a[maxn] , dp[maxn][24] , n;
void init()
{
	for(int i = 1 ; i<=n ; i++)
	{
		dp[i][0] = a[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 RMQ(int l,int r)
{
	int k = 0 ;
	while( 1<<(k+1) <=(r-l+1)) k++;
	return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lower_b(int l,int r,int ans)
{
	int s = r+1;
	while(l<=r)
	{
		int mid = (l+r)>>1;
		if(RMQ(l,mid)<=ans)
		{
			r = mid - 1;
			s = mid;
		}
		else
		{
			l = mid + 1;
		}
	}
	return s;
}
int main()
{
	int t;
	while(scanf("%d",&t)!=EOF)
	{
		while(t--)
		{
			mes(dp);
			mes(a);
			scanf("%d",&n);
			for(int i = 1 ; i <= n ; i++)
			{
				scanf("%d",&a[i]);
			}
			init();
			int m,ans;
			scanf("%d",&m);
			while(m--)
			{
				int L,R;
				scanf("%d%d",&L,&R);
				ans = a[L];
				L++;
				while(L<=R&&ans)
				{
					L = lower_b(L,R,ans);
					if(L<=R)
					{
						ans%=a[L];
						L++;
					}
				}
				printf("%d\n",ans);
			}
			
		}
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值