2016 ACM/ICPC Asia Regional Dalian Online 1008 Function 二分+RMQ

Time Limit: 7000/3500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 2229    Accepted Submission(s): 252


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) (1lrN) is defined as:
F(l,r)={AlF(l,r1) modArl=r;l<r.
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(1N100000).
  The second line contains N space-separated positive integers: A1,,AN (0Ai109).
  The third line contains an integer M denoting the number of queries. 
  The following M lines each contain two integers l,r (1lrN), 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
 
题意:给你一个n个数的序列,以及m个查询,每次查询一个区间[l,r],求a[l]%a[l+1]%a[l+2]...%a[r]
思路:易知,比当前大的数取模没意义,实际取模的次数是log次(取模至少会减少一半),那么问题就转化为如何在所查询的区间跳着来取模,每次只对比当前小的数取模
iky:::设ans为当前的值,上一次取模的位置为p,那么我们只需要在p的右边找到一个数比ans小的第一个数,ans对那么数取模,p跳到那么位置即可。最多跳log次,每次二分一个log,复杂度就是nloglog
 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <algorithm>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int N = 2e5 + 100;
int n, m;
int a[N], mm[N], mi[N][25];

void initRMQ(int n, int b[]) {
        mm[0] = -1;
        for(int i = 1; i <= n; ++i) {
            mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
            mi[i][0] = b[i];
        }
        for(int j = 1; j <= mm[n]; ++j)
            for(int i = 1; i + (1 << j) - 1 <= n; ++i)
            mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j-1))][j - 1]);
}
int rmq(int x, int y) {
        if(x > y) return 0x3f3f3f3f;
        int k = mm[y - x + 1];
        return min(mi[x][k], mi[y - (1 << k) + 1][k]);
}
int calc(int l, int r) {
        int p = l, ans = a[l];
        while(p < r) {
            int L = 1, R = r - p + 1, tmp = R;
            while(L < R) {
                int M = (L + R) >> 1;
                if(rmq(p + 1, p + M) <= ans) R = M;
                else L = M + 1;
            }

            if(L == tmp) return ans%a[r];
            p = p + L; //cout << p << endl;
            ans %= a[p];
        }
        return ans%a[r];
}
void solve() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        int l, r;
        initRMQ(n, a);
        scanf("%d", &m);
        for(int i = 1; i <= m; ++i) {
                scanf("%d%d", &l, &r);
                if(l == r) printf("%d\n", a[l]);
                else  printf("%d\n", calc(l, r));
        }
}
int main() {
#ifdef LOCAL
    freopen("in", "r", stdin);
#endif
    int cas;
    while(~scanf("%d", &cas)) {
        while(cas --) {
            solve();
        }
    }
    return 0;
}
View Code

 

posted @ 2016-09-11 10:36  JL_Zhou  阅读(275)  评论(0编辑  收藏  举报