您的位置:首页 > 理论基础 > 计算机网络

HDU 5875 Function 2016亚洲区域赛大连网络赛

2017-08-28 21:32 357 查看
题意:给你n个数和询问,让你回答对一段区间去膜的结果。

题解:这个题的关键,在于我们要注意一个数取模的一个性质就是说 一个数对一个比这个数大的数取模这个数不变,如果对一个比这个数小的数取模,这个数最少变成原来的 1 / 2.有了这个性质我们不难发现一个数取模的收敛速度是非常快的。在 logn时间内就可以收敛到很小,这样我们就可以找一个区间内比这个数小的数去取模大的数我们就可以不管。不断寻找比取模完的数更小的,最接近这个数的数去取模。 怎么找呢 ? 我们可以二分第一个取模位置,通过 ST 表或者线段树树状数组之类的数据结构维护一个区间最小值即可

ps : 学到一个求log 下取整的递推方法 以 log2为例          lg2[i] = lg2[i / 2] + 1

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;
const int maxn = 1e5 + 10;
const int INF = 1e9 + 7;
int lg2[maxn] = {0};
int st[maxn][40] = {0};
int a[maxn] = {0};
int n;
void init () {
for (int j = 1;(1 << j) <= n; ++ j){
for (int i = 1;i + (1 << j) - 1 <= n; ++ i) {
st[i][j] = min (st[i][j - 1],st[i + (1 << (j - 1))][j - 1]);
}
}
}
int rmq (int l,int r) {
int len = (r - l + 1);
len = lg2[len];
int ans = min (st[l][len],st[r - (1 << len) + 1][len]);
return ans;
}
int main () {
ios_base :: sync_with_stdio(false);
int t;
cin >> t;
for (int i = 2;i < maxn; ++ i) {
lg2[i] = lg2[i / 2] + 1;
}
while (t --) {
cin >> n;
memset (st,0,sizeof (st));
memset (a,0,sizeof (a));
for (int i = 1;i <= n; ++ i) {
cin >> a[i];
st[i][0] = a[i];
}
init();
int q;
cin >> q;
while (q --) {
int l,r;
cin >> l >> r;
if (l == r) {
cout << a[l] << endl;
continue ;
}
int ans = a[l];
int L = l + 1;
int R = r;
int flag = 1;
while (flag) {
while (L < R) {
int mid = (L + R) >> 1;
if (rmq (L,mid) <= ans) R = mid;
else {
if (rmq (mid + 1,R) > ans) {
flag = 0;
break;
}
else {
L = mid + 1;
}
}
}
if (flag) ans %= a[L];
L ++,R = r;
if (L > r || ans == 0) break;
}
cout << ans << endl;
}
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu datestruct 算法 思维