2016大连网络赛 H题 传送门:HDU - 5875
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:
\[ F(l,r)=\begin{cases} A_l & l=r \\ F(l,r-1) mod A_r & l<r \\ \end{cases}\]
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: \(A_1,…,A_N (0≤A_i≤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
Source
2016 ACM/ICPC Asia Regional Dalian Online
题目大意:
- 给定序列\(A_N\),操作\(F(l,r)\)表示查询\(A_l mod A_{l+1} mod……mod A_{r}\)
基本思路:
- 首先要分析多次取模操作的特征。\(a mod b\)对于a<b时无意义,\(a mod b mod c\)对于b<c无意义。所以,区间里有效取模应该是递减的。
- 再进一步思考可以发现 取模过程的递减非常快 ,至少也是\(a mod b > a/2\),注意到一旦a变成0就可以不考虑后面的区间,也就是说施加取模次数是log级的,最多也就30次左右。
具体实现:
- 预处理是个很大的问题,最简单的办法是 记录\(A_i\)后面第一个比\(A_i\)小的数的位置 ,\(n^2\)复杂度明显太慢。但仔细一想,只有非常极端的情况复杂度才会达到\(n^2\)。(然后居然真的就这么过了哈哈哈)
- 考虑更优化的预处理方法:每次只需要知道这个数后面第一个比它小的数,有点类似区间最小值,只不过要从左到右选择区间,在RMQ上进行修改即可。
- 查询过程就很容易了实现了,每次跳到下一个位置,当前值为0或者超出区间则退出。
注意事项:
- 根据题意(和做题习惯),查询操作应该是很多,所以一定要预处理。每次查询都找一边当前区间的LIS的做法是不行的。
- 所以这不就是个区间LIS么。
Codes:
暴力版本:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int main()
{
int t,n,m,a[MAXN],nex[MAXN];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; ++i)
scanf("%d",&a[i]);
for(int i=1; i<=n; ++i)
{
nex[i] = 0;
for(int j=i+1; j<=n; ++j)
if(a[i] > a[j])
{
nex[i] = j;
break;
}
}
scanf("%d",&m);
while(m--)
{
int l,r;
scanf("%d %d",&l,&r);
int ans = a[l],now = nex[l];
while(now <= r && now != 0)
{
ans %= a[now];
if(ans == 0)
break;
now = nex[now];
}
printf("%d\n",ans);
}
}
return 0;
}
修改RMQ版本:
咕咕咕