Full_of_Boys训练3总结

题目来源: 2016-2017 ACM-ICPC Pacific Northwest Regional Contest

J.Shopping

每次找到区间内最左边的小于x的数,然后%一下它,重复以上操作就行了。所以只需要实现一个区间询问最左边的小于x的值就可以了。可以证明每次操作最多log次

解法1:分块。块外暴力,块内提前排好序二分。写挫了莫名t。

解法2:线段树。维护一下区间最小值,显然如果左边的最小值小于等于x那就朝左边递归,否则右边,便可以完成这个操作。

解法3:st表。又不用修改。st表干掉一个log

code:

解法1:挫了不贴了。

解法2:

#include <cstdio>
#include <algorithm>
#define pb(x) push_back(x)
#define rg register
const int maxn = 2e5 + 100;
typedef unsigned long long ll;
inline int readint(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
inline ll readll(){
    char c=getchar();ll x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
inline void write(ll x){
    if(x>=10LL) write(x/10LL);
    putchar('0'+x%10LL);
}
using namespace std;
int n, q;
ll a[maxn];
struct seg{int l, r; ll x;} tr[maxn << 2];
inline void build(int p, int l, int r) {
    tr[p].l = l; tr[p].r = r;
    if(l == r){
        tr[p].x = a[l]; return;
    }
    int mid = (l + r) >> 1;
    build(p<<1, l, mid);
    build(p<<1|1, mid+1, r);
    tr[p].x = min(tr[p<<1].x, tr[p<<1|1].x);
}
inline ll ask_mn(int p, int l, int r) {
    if(tr[p].l == l && tr[p].r == r) return tr[p].x;
    int mid = (tr[p].l + tr[p].r) >> 1;
    if(r <= mid) return ask_mn(p<<1, l, r);
    else if(l > mid) return ask_mn(p<<1|1, l, r);
    else return min(ask_mn(p<<1, l, mid), ask_mn(p<<1|1, mid+1, r));
}
inline ll fd(ll x, int L, int R) {
    if(L == R) return L;
    int mid =(L + R) >> 1;
    if(ask_mn(1, L, mid) <= x) return fd(x, L, mid);
    else return fd(x, mid+1, R);
}
inline ll solve(ll x, int L, int R){
    while(ask_mn(1, L, R) <= x) x %= a[fd(x, L, R)];
    return x;
}
int main() {
    n = readint(), q = readint();
    for(int i = 1; i <= n; ++i) a[i] = readll();
    build(1, 1, n);
    while(q--) { ll x; int L, R;
        x = readll(), L = readint(), R = readint();
        write(solve(x, L, R)); puts("");
    }
    return 0;
}

解法3:

#include <cstdio>
#include <algorithm>
#include <iostream>
#define pb(x) push_back(x)
#define rg register
const int maxn = 2e5 + 100;
typedef unsigned long long ll;
inline int readint(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
inline ll readll(){
    char c=getchar();ll x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
inline void write(ll x){
    if(x>=10LL) write(x/10LL);
    putchar('0'+x%10LL);
}
using namespace std;
int n, q;
ll a[maxn], st[maxn][25];
inline void RMQ_init(){
    for(int i = 0; i <= n; ++i) st[i][0] = a[i];
    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]);
        }
    }
}
inline ll RMQ(int u, int v){
    int k = (int)(log(v-u+1.0)/log(2.0));
    return min(st[u][k], st[v-(1<<k)+1][k]);
}
inline ll fd(ll x, int L, int R) {
    if(L == R) return L;
    int mid =(L + R) >> 1;
    if(RMQ(L, mid) <= x) return fd(x, L, mid);
    else return fd(x, mid+1, R);
}
inline ll solve(ll x, int L, int R){
    while(RMQ(L, R) <= x) x %= a[fd(x, L, R)];
    return x;
}
int main() {
    n = readint(), q = readint();
    for(int i = 1; i <= n; ++i) a[i] = readll();
    RMQ_init();
    while(q--) { ll x; int L, R;
        x = readll(), L = readint(), R = readint();
        write(solve(x, L, R)); puts("");
    }
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/RRRR-wys/p/8972815.html