1. 程式人生 > 其它 >【分塊】LOJ分塊入門九

【分塊】LOJ分塊入門九

分塊入門九

題目轉移陣

思路整理

眾數,就是給定一段範圍,在這段範圍所出現次數最多的數字(如果出現相同次數相同的),那麼怎麼才能稱上是最多,最多是怎麼來的?

最多是比較來的,通過每一種數字的數量的比較而來。

那麼我們就需要能夠算出所有數字在任意給定的區間的數量。

那要怎麼做

首先,用vector存好每一個數字在給定區域內所有出現的位置

宣告vector

vector<int> g[maxn];

g[x]存放的是值為x在區間的出現的所有的位置的有序序列(實際上是x離散化所得到的下標,我們可以通過另開一個數組去記錄x所對應的value,val[x]=i)

但如果這樣的話,真的合適嗎?(相當於桶排,必然會帶來空間的浪費)。

所以應該使用離散化的做法。

而離散化的物件是一個已經存在的數字,

而我們要如何去確定一個數字已經存在呢?

用map或者unordered _map

cin>>a[i];
if(!mp(a[i]))
{
    mp[a[i]]=++cnt;//賦予a[i]一個新的下標
    val[cnt]=a[i];同時用一個數組存放這個下標對應的值
}
g[mp[a[i]]].push_back(i);

但這裡仍然有個問題,也是這道題在LOJ上提交只能得到80分左右的原因。

就是用map(即便是map)取查詢一個元素的時候,它所帶來的代價並不是O(1),因而當多次使用map或者unordered_map的時候必然會帶來一定的時間損耗。

因而這裡可以再做一個調整

            if (!mp[ A[j] ])
            {
            	mp[ A[j] ] = ++cnt;
            	val[cnt] = A[j];
			}
                
            A[j] = mp[A[j]];
            pos[ A[j] ].push_back(j);

方便以後用二分搜尋快速找到某個數在區間l到r的所有個數

(在整體區間中找到第一個大於位置r的位置的下標(即便是找到符合條件的,也會往外再跳一個,這樣方便到時候不用再去做減一的操作),並以此減去第一個大於或等於位置l的位置的下標,從而獲取個數。

int query(int l,int r,int x)
{
     greater_bound(g[x].begin(),g[x].end(),r)-lower_bound(g[x].begin(),g[x].end(),l)
}

整體思路

  1. 預先處理地動態處理好塊l到塊r的眾數

  2. 然後查l到r的眾數,分三個區域來做

  3. 就是先用l到r區域之間的整塊的眾數提取出來扔到二分搜尋函式裡面跑一遍,得到個數(這個預先存好的眾數答案在這個區間段是無敵的)。

  4. 然後再把左右倆個散塊的眾數提取出來各跑一遍

  5. 得到三個答案然後再取最優

80分程式碼

#include <bits/stdc++.h>
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define pi acos(-1.0)
#define PII pair<int,int>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define de() cout<<"debug"<<endl;
using namespace std;
const int N = 1e5 + 10, KN = 4E4 + 10, FN = 4005;
int t, blen, n, A[N], bel[N], st[KN], ed[KN], f[FN][FN],cnt[N];
unordered_map<int, int> mp, pcnt;
vector<int> pos[N];
void predo(int x) {
    memset(cnt, 0, sizeof(cnt));
    int mmax = 0, ans = 0;
    for (int i = st[x]; i <= n; i++) {
        cnt[ mp[A[i]] ]++;
        int p = bel[i];
        if (cnt[ mp[A[i]] ] > mmax || (cnt[ mp[A[i]] ] == mmax && ans > A[i])) {
            mmax = cnt[ mp[A[i]] ];
            ans = A[i];
        }
        f[x][p] = ans;
    }
}
inline int get_num(int l, int r, int x) {
    return upper_bound(pos[ mp[x] ].begin(), pos[ mp[x] ].end(), r) - lower_bound(pos[ mp[x] ].begin(),
            pos[ mp[x] ].end(), l);
}
inline int ask(int l, int r) {
    int res, maxn = 0, val;

    if (bel[l] == bel[r]) {
        repd(i, l, r) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val > A[i])) {
                maxn = num;
                val = A[i];
            }
        }
        res = val;
    } else {
        if (bel[l] + 1 <= bel[r] - 1) {
            maxn = get_num(l, r, f[ bel[l] + 1 ][ bel[r] - 1 ]);
            val = f[ bel[l] + 1 ][ bel[r] - 1 ];
        }

        repd(i, l, ed[ bel[l] ]) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val > A[i])) {
                maxn = num;
                val = A[i];
            }
        }

        repd(i, st[ bel[r] ], r) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val > A[i])) {
                maxn = num;
                val = A[i];
            }
        }
        res = val;
    }

    return res;
}
int main() {
    cin >> n;
    blen = 30;
    t = n / blen;
    repd(i, 1, t) {
        st[i] = (i - 1) * blen + 1;
        ed[i] = i * blen;
    }

    if (ed[t] < n)
        t++, st[t] = ed[t - 1] + 1, ed[t] = n;

    int cnt = 0;
    repd(i, 1, t) {
        repd(j, st[i], ed[i]) {
            scanf("%d", &A[j]);

            if (!mp[ A[j] ])
                mp[ A[j] ] = cnt++;

            pos[ mp[A[j]] ].push_back(j);
            bel[j] = i;
        }
    }
    repd(i, 1, t)
    predo(i);
    repd(i, 1, n) {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%d\n", ask(l, r));
    }
    return 0;
}

100程式碼

#include <bits/stdc++.h>
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a)
#define gcd(a,b) __gcd(a,b)
#define pi acos(-1.0)
#define PII pair<int,int>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define MAX 1000005
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define lowbit(x) (x&-x)
#define de() cout<<"debug"<<endl;
using namespace std;
const int N = 1e5 + 10, KN = 4E4 + 10, FN = 2005;//1e5/80
int t, blen, n, A[N], bel[N], st[KN], ed[KN], f[FN][FN],cnt[N];
ll val[N];
unordered_map<int, int> mp;
vector<int> pos[N];
void predo(int x) {
    memset(cnt, 0, sizeof(cnt));
    int mmax = 0, ans = 0;
    for (int i = st[x]; i <= n; i++) {
        cnt[ A[i] ]++;
        int p = bel[i];
        if (cnt[ A[i] ] > mmax || (cnt[ A[i] ] == mmax && val[ ans ] > val[ A[i] ])) {
            mmax = cnt[ A[i] ];
            ans = A[i];
        }
        f[x][p] = ans;
    }
}
inline int get_num(int l, int r, int x) {
    return upper_bound(pos[ x ].begin(), pos[ x ].end(), r) - lower_bound(pos[ x ].begin(),pos[ x ].end(), l);
}
inline ll ask(int l, int r) {
    int maxn = 0, ans;
    ll res;
    if (bel[l] == bel[r]) {
        repd(i, l, r) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val[ans] > val[A[i]] )) {
                maxn = num;
                ans = A[i];
            }
        }
        res = val[ ans ];
    } else {
        if (bel[l] + 1 <= bel[r] - 1) {
            maxn = get_num(l, r, f[ bel[l] + 1 ][ bel[r] - 1 ]);
            ans = f[ bel[l] + 1 ][ bel[r] - 1 ];
        }

        repd(i, l, ed[ bel[l] ]) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val[ans] > val[ A[i] ])) {
                maxn = num;
                ans = A[i];
            }
        }

        repd(i, st[ bel[r] ], r) {
            int num = get_num(l, r, A[i]);

            if (num > maxn || (num == maxn && val[ans] > val[ A[i] ])) {
                maxn = num;
                ans = A[i];
            }
        }
        res = val[ ans ];
    }

    return res;
}
int main() {
    cin >> n;
    blen = 80;
    t = n / blen;
    repd(i, 1, t) {
        st[i] = (i - 1) * blen + 1;
        ed[i] = i * blen;
    }

    if (ed[t] < n)
        t++, st[t] = ed[t - 1] + 1, ed[t] = n;

    int cnt = 0;
    repd(i, 1, t) {
        repd(j, st[i], ed[i]) {
            scanf("%d", &A[j]);

            if (!mp[ A[j] ])
            {
            	mp[ A[j] ] = ++cnt;
            	val[cnt] = A[j];
			}
                
            A[j] = mp[A[j]];
            pos[ A[j] ].push_back(j);
            bel[j] = i;
        }
    }
    repd(i, 1, t)
    predo(i);
    repd(i, 1, n) {
        int l, r;
        scanf("%d%d", &l, &r);
        printf("%lld\n", ask(l, r));
    }
    return 0;
}