您的位置:首页 > 其它

HDU 5875 Function(二分区间+RMQ)——2016 ACM/ICPC Asia Regional Dalian Online

2016-09-12 12:52 645 查看
此文章可以使用目录功能哟↑(点击上方[+])




 HDU 5875 Function

Accept: 0    Submit: 0

Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)




 Problem Description

The shorter, the simpler. With this problem, you should be convinced of this truth.
You are given an array A of N postive integers, and M queries in the form (l,r). A function F(l,r) (1≤l≤r≤N) is defined as:



You job is to calculate F(l,r), for each query (l,r).



 Input

There are multiple test cases.
The first line of input contains a integer T, indicating number of test cases, and T test cases follow. 
For each test case, the first line contains an integer N(1≤N≤100000).
The second line contains N space-separated positive integers: A1,…,AN (0≤Ai≤10^9).

The third line contains an integer M denoting the number of queries. 

The following M lines each contain two integers l,r (1≤l≤r≤N), representing a query.



 Output

For each query(l,r), output F(l,r) on one line.



 Sample Input

1

3

2 3 3

1

1 3



 Sample Output

2



 Problem Idea

解题思路:

【题意】

给你n个正整数,q次询问,每次询问给你l和r,求al mod al+1
mod ... mod ar

【类型】

二分区间+RMQ

【分析】

对于此题,还是觉得比较坑的,一方面数据太水,对于别人O(n^2)的做法居然轻易过了

O(n^2)做法:一个小的数mod大于它的数等于它本身,考虑从左往右遍历,但是要每次跳过比它大的那些数,直接指向它右边第一个比它小的

显然这样做的复杂度是不定的……最坏的情况还是O(N×M),即所有的数据都是降序的情况

例如如果有一组数据是长度为1e5的降序数组+1e5个长度为1e5的查询就必定T了

所以,归根结底,此题的正解应该还是二分区间+RMQ

但RMQ还不能用log来计算区间长,否则一样是TLE,即RMQ用下面这种实现是不行的,可能是math.h里的log运算复杂度比较高吧

void RMQ()   		//预处理  O(nlogn)
{
int i,j;
int m=(int)(log(n*1.0)/log(2.0));
for(i=1;i<=n;i++)
minnum[i][0]=s[i];
for(j=1;j<=m;j++)
for(i=1;i+(1<<j)-1<=n;i++)
minnum[i][j]=min(minnum[i][j-1],minnum[i+(1<<(j-1))][j-1]);
}
int Ask_MIN (int a,int b) 	//O(1)
{
int k=int(log(b-a+1.0)/log(2.0));
return min(minnum[a][k],minnum[b-(1<<k)+1][k]);
}
换成下面这种就可以过了

void RMQ()   		//预处理  O(nlogn)
{
for(int i=1;i<=n;i++)
minnum[i][0]=s[i];
for(int j=1;(1<<j)<=n;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
minnum[i][j]=min(minnum[i][j-1],minnum[i+(1<<(j-1))][j-1]);
}
int Ask_MIN (int l,int r) 	//O(1)
{
int k=0;
while((1<<(k+1))<=r-l+1)
k++;
return min(minnum[l][k],minnum[r-(1<<k)+1][k]);
}
再来具体讲一下做法



【时间复杂度&&优化】

O(n×logn×logn×logn)

题目链接→HDU 5875 Function



 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 20005;
const int inf = 1000000007;
const int mod = 1000000007;
int s
,n,minnum
[20];
void get_val(int &ret)
{
int sgn=1;
char c;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-')
sgn=-1,ret=0;
else
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
ret=ret*10+c-'0';
ret*=sgn;
}
void RMQ() //预处理 O(nlogn) { for(int i=1;i<=n;i++) minnum[i][0]=s[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) minnum[i][j]=min(minnum[i][j-1],minnum[i+(1<<(j-1))][j-1]); } int Ask_MIN (int l,int r) //O(1) { int k=0; while((1<<(k+1))<=r-l+1) k++; return min(minnum[l][k],minnum[r-(1<<k)+1][k]); }
int binary(int l,int r)
{
int a,b,mid,ans=s[l];
while(l<r)
{
a=l+1;b=r;
while(a<b)
{
mid=(a+b)/2;
if(Ask_MIN(a,mid)<=ans)
b=mid;
else if(Ask_MIN(mid+1,b)<=ans)
a=mid+1;
else
return ans;
}
ans%=s[a];
l=a;
}
return ans;
}
int main()
{
int t,m,i,l,r;
get_val(t);
while(t--)
{
get_val(n);
for(i=1;i<=n;i++)
get_val(s[i]);
RMQ();
get_val(m);
for(i=0;i<m;i++)
{
get_val(l);
get_val(r);
printf("%d\n",binary(l,r));
}
}
return 0;
}
菜鸟成长记
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐