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;
}
题解:这个题的关键,在于我们要注意一个数取模的一个性质就是说 一个数对一个比这个数大的数取模这个数不变,如果对一个比这个数小的数取模,这个数最少变成原来的 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;
}
相关文章推荐
- 【2016-大连赛区网络赛-H】优化(Function,hdu 5875)
- HDU 5875 Function -2016 ICPC 大连赛区网络赛
- 2016 ICPC 大连网络赛 HDU 5875 Function
- hdu 5875 Function 2016ACM/ICPC大连赛区网络赛1008
- HDU 5875 Function 大连网络赛 线段树
- HDU 5873 - Football Match【2016大连区域赛网络赛1006】
- HDU 5875 Function (2016年大连网络赛 H 线段树+gcd)
- HDU 5875 Function 大连网络赛
- hdu 5875 Function -线段树+取余 -ICPC网络赛大连赛区
- HDU 5875 Function 大连网络赛 线段树
- HDU-5877-Weak Pair【树状数组】【离散化】【DFS】【2016大连网络】【好题】
- HDU 5877 2016大连网络赛 Weak Pair(树状数组,线段树,动态开点,启发式合并,可持久化线段树)
- 2016 ICPC 大连网络赛 HDU 5873 Football Games
- HDU 5900 QSC and Master(2016亚洲区沈阳站网络赛)
- 【2016-大连赛区网络赛-I】补图最短路(Sparse Graph,hdu 5876)
- HDU 5875 2016网预 大连
- HDU 5879 - Cure【2016 ACM 区域赛青岛赛区网络赛】
- 2016 ICPC 大连网络赛 HDU 5874 Friends and Enemies
- HDU 5971 Wrestling Match 2016大连区域赛
- 2016 ICPC 大连网络赛 HDU 5877 Weak Pair