HDU 5875 Function 单调栈 + 技巧 区间和

                                                    Function

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


 

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≤lrN) is defined as:
F(l,r)={AlF(l,r−1) 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(1≤N≤100000).
  The second line contains N space-separated positive integers: A1,…,AN (0≤Ai≤109).
  The third line contains an integer M denoting the number of queries.
  The following M lines each contain two integers l,r (1≤lrN), 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

 

解析

因为%在不断地有效的取余是最多取余lgmax(Ai)  (约等于 32) 次,所以只要用单调栈预处理出一个next数组记录比当前数小或等于的位置,然后 对于每次l,r 查询, 从l 开始跳转,不断跳转比当前数小的值

这题也可以用线段树,先查询l+1 ~ r中 比a[l] 小的第一个值

 

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int maxn = 1e5+100;
const int INF = 0x3f3f3f3f;

int n,T;
int a[maxn],child[maxn];
stack <int> s;
int main()
{
  scanf("%d",&T);
  while(T--)
  {
    scanf("%d",&n);
    for(int i = 0; i < n; i++)  scanf("%d",&a[i]);
    while(!s.empty())  s.pop();
    memset(child,-1,sizeof(child));
    for(int i = 0; i < n; i++)
    {
      while(!s.empty() && a[s.top()] >= a[i]) {child[s.top()] = i;s.pop();}
      s.push(i);
    }
    int q;
    scanf("%d",&q);
    while(q--)
    {
      int l,r;
      scanf("%d%d",&l,&r);
      l--,r--;
      if(l == r)  printf("%d\n",a[l]);
      else
      {
        int t = child[l];
        int ans = a[l];
        while(t != -1 && t <= r && t < n)
        {
           ans %= a[t];
           t = child[t];
        }
       printf("%d\n",ans);
      }
    }
  }
  return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值