CodeChef - QCHEF 分块

题目链接:http://vjudge.net/problem/174774/origin

题意:给定一个长度为n的序列a[],序列的值不大于m,现在有k个询问,每个询问给定(l,r).让你求出max{|x − y| : Li ≤ x, y ≤ Ri and Ax = Ay}。即区间[L,R]中值相同时,位置差的最大值

思路:分块,因为不带修改,所以我们就可以做预处理。求出last,first,Ans。 last[i][j]:值i在第j块最后出现的位置。first[i][j]:值i在第j块最早出现的位置。Ans[i][j]:第i块到第j块的值相同的最大位置差。

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<queue>
#include<math.h>
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 100000 + 10;
int belong[MAXN], block, num, L[MAXN], R[MAXN];
int n, m, q;
int a[MAXN], last[MAXN][500], first[MAXN][500], Ans[500][500];
int tim[MAXN], times, Pos[MAXN];
int cal(int st, int ed){
    int ans = 0;
    for (int i = L[st]; i <= R[st]; i++){
        ans = max(ans, last[a[i]][ed] - i);
    }
    return ans;
}
void build(){
    block = (int)sqrt(n + 0.5);
    num = n / block; if (n%block){ num++; }
    for (int i = 1; i <= num; i++){
        L[i] = (i - 1)*block + 1; R[i] = i*block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++){
        belong[i] = ((i - 1) / block) + 1;
    }
    memset(last, 0, sizeof(last)); memset(first, 0, sizeof(first));
    memset(Ans, 0, sizeof(Ans)); times = 0;
    for (int i = 1; i <= n; i++){
        last[a[i]][belong[i]] = i;
    }
    for (int i = n; i>0; i--){
        first[a[i]][belong[i]] = i;
    }
    for (int i = 1; i <= m; i++){
        for (int j = 1; j <= num; j++){
            if (!last[i][j]){ last[i][j] = last[i][j - 1]; }
        }
        for (int j = num; j; j--){
            if (!first[i][j]){ first[i][j] = first[i][j + 1]; }
        }
    }
    for (int i = num; i; i--){
        for (int j = i; j <= num; j++){
            Ans[i][j] = max(max(Ans[i + 1][j], Ans[i][j - 1]), cal(i, j));
        }
    }
}
int query(int st, int ed){
    int ans = 0; times++;
    if (belong[st] == belong[ed]){
        for (int i = st; i <= ed; i++){
            if (tim[a[i]] != times){ Pos[a[i]] = i; tim[a[i]] = times; }
            else{ ans = max(ans, i - Pos[a[i]]); }
        }
        return ans;
    }
    for (int i = st; i <= R[belong[st]]; i++){
        if (tim[a[i]] != times){ Pos[a[i]] = i; tim[a[i]] = times; }
        else{ ans = max(ans, i - Pos[a[i]]); }
        ans = max(ans, last[a[i]][belong[ed] - 1] - i);
    }
    ans = max(ans, Ans[belong[st] + 1][belong[ed] - 1]);
    for (int i = L[belong[ed]]; i <= ed; i++){
        if (tim[a[i]] != times){ Pos[a[i]] = i; tim[a[i]] = times; }
        else{ ans = max(ans, i - Pos[a[i]]); }
        ans = max(ans, i - first[a[i]][belong[st] + 1]);
    }
    return ans;
}
int main(){
    //#ifdef kirito
    //    freopen("in.txt", "r", stdin);
    //    freopen("out.txt", "w", stdout);
    //#endif
    //    int start = clock();
    while (~scanf("%d%d%d", &n, &m, &q)){
        for (int i = 1; i <= n; i++){ scanf("%d", &a[i]); }
        build(); int st, ed;
        for (int i = 1; i <= q; i++){
            scanf("%d%d", &st, &ed);
            printf("%d\n", query(st, ed));
        }
    }
    //#ifdef LOCAL_TIME
    //    cout << "[Finished in " << clock() - start << " ms]" << endl;
    //#endif
    return 0;
}
时间: 2024-11-09 04:45:43

CodeChef - QCHEF 分块的相关文章

[codechef FNCS]分块处理+树状数组

题目链接:https://vjudge.net/problem/CodeChef-FNCS 在一个地方卡了一晚上,就是我本来以为用根号n分组,就会分成根号n个.事实上并不是....因为用的是根号n下取整分组,得到的组数要用n/floor(sqrt(n))具体计算. 另外还有各种奇怪的bug--包括unsigned long long什么的--orz #include<bits/stdc++.h> using namespace std; typedef unsigned long long u

CodeChef FNCS (分块+树状数组)

题目:https://www.codechef.com/problems/FNCS 题解: 我们知道要求区间和的时候,我们用前缀和去优化.这里也是一样,我们要求第 l 个函数到第 r 个函数 [l, r] 的函数和,那么我们可以用 sum[r] - sum[l-1] 来求得. 由于这个数据量有点大,所以我们将函数分块. 例如样例: 1 3 有5个函数,那么我们分成3块.{ [1 3] , [2 5] }, { [4 5], [3 5] }, { [1 2] }.每一块对应都有一个sum ,这时如

CodeChef COUNTARI Arithmetic Progressions(分块 + FFT)

题目 Source http://vjudge.net/problem/142058 Description Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can choose three numbers such that they are three consecutive terms of an arithmetic progression. Meaning that, how many trip

CodeChef - COUNTARI FTT+分块

Arithmetic Progressions Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can choose three numbers such that they are three consecutive terms of an arithmetic progression. Meaning that, how many triplets (i, j, k) are there such t

【xsy2111】 【CODECHEF】Chef and Churus 分块+树状数组

题目大意:给你一个长度为$n$的数列$a_i$,定义$f_i=\sum_{j=l_i}^{r_i} num_j$. 有$m$个操作: 操作1:询问一个区间$l,r$请你求出$\sum_{i=l}^{r} f_i$. 操作2:将$a_x$变成$y$. 此题貌似正常做都不是很好做,考虑用一些奇奇怪怪的做法(比如说分块) 考虑到此题数列在不断地变化,我们考虑用树状数组来维护序列$a$,查询$f_i$的值可以在$O(log n)$的时间内完成. 如果这么做,单次询问的复杂度是$O(n log n)$的,

Maximum number, GCD condition (codechef March Challenge 2014)

题目 : http://acm.bnu.edu.cn/v3/problem_show.php?pid=40489 最近做到的一道蛮有意思的题目(codechef现在的题目确实很赞了) 题意 :中文题面 (cc的一大好处就是有中文翻译,嘿嘿) 区间Max = max{a_i|gcd(a_i, g) > 1 && x <= i <= y} 做法 : 一开始我是用分块做的,复杂的O(m * sqrt(n) * C) C 是所含不同素数的个数, C大概最大只有6或7吧 然后裸裸的

CodeChef CBAL

题面: https://www.codechef.com/problems/CBAL 题解: 可以发现,我们关心的仅仅是每个字符出现次数的奇偶性,而且字符集大小仅有 26, 所以我们状态压缩,记 a[i]表示 s[1..i]所有字符的奇偶性状态, 那么子串 s[L..R]是平衡字符串当且仅当a[L-1]=a[R]. 我们对 a 离散化后就可以让其在[1,n]的范围内. 如果没有强制在线,那么我们很容易用莫队算法解决. 记录当前范围所有状态的出现位置下标的 0~2 次方之和, 利用(a-b)2=a

CC countari &amp; 分块+FFT

题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: 一个块内直接枚举统计三个或两个在块内的. 只有一个在当前块我们假设它是中间那个,对左右其它块做卷积. 但是还是感觉复杂度有点玄学啊... 我比较傻逼...一开始块内统计根本没有想清楚...最后做卷积硬生生把复杂度变成了 $\sqrt{N}*N*log(N)$... 改了一个晚上终于没忍住看标程...

SPOJ PGCD - Primes in GCD Table (好题! 莫比乌斯反演+分块求和优化)

PGCD - Primes in GCD Table Johnny has created a table which encodes the results of some operation -- a function of two arguments. But instead of a boring multiplication table of the sort you learn by heart at prep-school, he has created a GCD (greate