CodeChef Chef and Problems(分块)

链接

题意:
             n n 个数k个查询,每次查询在 [l,r] [ l , r ] 中满足 ai=ajji a i = a j 时 j − i 的最大值。

思路:
             对整个数组分块,设块的大小为 sz s z ,总共有 tot t o t 块,那么记 f[i][j] f [ i ] [ j ] :从第 i i 块到第j块满足 ax=ay a x = a y yx y − x 的最大值。这样对于区间 [l,r] [ l , r ] 的查询,在两端的直接暴力查找,对于在中间的直接是 f[l/sz+1][r/sz1] f [ l / s z + 1 ] [ r / s z − 1 ] 。时间复杂度有点高, O(nnlogn) O ( n n log ⁡ n ) , 开个输入挂进去。

#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;

int a[maxn], b[1110][1110], vis[maxn];
vector<int> vec[maxn];
int n, m, k, l, r, block_size;

inline int solve(int flag, int L, int R, int l, int r) {
    int ans = 0;
    for(int i = L; i <= R; i++) {
        int x = a[i];
        if(flag == 1) {
            int i1 = upper_bound(vec[x].begin(), vec[x].end(), r) - vec[x].begin() - 1;
            if(i1 >= 0 && vec[x][i1] >= l) ans = max(ans, abs(i - vec[x][i1]));
        } else {
            int i2 = lower_bound(vec[x].begin(), vec[x].end(), l) - vec[x].begin();
            if(i2 != vec[x].size() && vec[x][i2] <= r) ans = max(ans, abs(i - vec[x][i2]));
        }
    }
    return ans;
}

inline int query(int l, int r) {
    int b1 = l / block_size;
    int b2 = r / block_size, ans = 0;

    if(b1 == b2) return solve(1, l, r, l, r);
    ///处理两端
    int l1 = (b1 + 1) * block_size - 1;
    int l2 = b2 * block_size;
    ans = max(ans, solve(1, l, l1, l, r));
    ans = max(ans, solve(0, l2, r, l, r));
    ///处理块与块之间
    if(b1 + 1 <= b2 - 1) ans = max(ans, b[b1 + 1][b2 - 1]);
    return ans;
}

const int MAX = 10000;
char buf[MAX], *ps = buf, *pe = buf + 1;
inline void rnext() {
    if(++ps == pe) pe = (ps = buf) + fread(buf, sizeof(char), sizeof(buf) / sizeof(char), stdin);
}
template <class T>
inline bool in(T &ans) {
    ans = 0;
    T f = 1;
    if(ps == pe) return false;//EOF
    do{
        rnext();
        if('-' == *ps) f = -1;
    } while(!isdigit(*ps) && ps != pe);
    if(ps == pe) return false;//EOF
    do {
        ans = (ans<<1)+(ans<<3)+*ps-48;
        rnext();
    } while(isdigit(*ps) && ps != pe);
    ans *= f;
    return true;
}

int main() {
    while(in(n)) {
        in(m); in(k);
        for(int i = 0; i < maxn; i++) vec[i].clear();
        memset(b, 0, sizeof b);
        for(int i = 0; i < n; i++) {
            in(a[i]);
            vec[a[i]].push_back(i);
        }
        block_size = 100;
        for(int i = 0; i < n; i += block_size) {
            int imax = 0;
            memset(vis, -1, sizeof vis);
            for(int j = i; j < n; j++) {
                if(vis[a[j]] == -1) vis[a[j]] = j;
                else imax = max(imax, j - vis[a[j]]);
                int &bs = b[i / block_size][j / block_size];
                bs = max(bs, imax);
            }
        }
        while(k--) {
            in(l); in(r); l--; r--;
            printf("%d\n", query(l, r));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值