• [NC] 仓鼠与珂朵莉-分块


    在这里插入图片描述
    给定一个长度为n的序列,m个询问
    每次给出一个区间,查找区间内x*cnt[x] 的最大值
    由于题目的限制,下一次询问的区间会受到上一次查询结果的影响,所以必须要进行强制在线处理

    首先将数列分成ceil(n/blk+1) 块,对于询问中b[l] + 1 -> b[r] - 1这一块中的答案我们可以通过预处理得到,这里的写法类似数列分块入门中的第九题查询区间众数

    然后需要做的就是暴力计算左右两边的小块的贡献
    在这个数据范围下,先进行离散化处理比较好,对于查询的结果可能比较大,所以数据类型上一定要开long long

    ll n,m,a[maxn],b[maxn];
    ll blk,mx[357][357],sum[357][maxn],id[maxn],c[357][maxn],cnt[maxn];
    vector<ll> vet;
    int get(ll x) {
    	return lower_bound(vet.begin(),vet.end(),x) - vet.begin() + 1;
    }
    void pre(int i) {
    	ll t = 0;
    	Clear(cnt,0);
    	for(int j = (i-1) * blk + 1; j<=n; j++) {
    		cnt[id[j]] ++;
    		t = max(t,cnt[id[j]] * a[j] * 1LL);
    		mx[i][b[j]] = t;
    	}
    }
    ll query(int l,int r) {
    	ll ret = 0;
    	if(b[l] == b[r]) { // in the same blk
    		for(int i=l; i<=r; i++) cnt[id[i]] = 0;
    		for(int i=l; i<=r; i++) cnt[id[i]] ++,ret = max(ret,cnt[id[i]] * a[i]);
    		for(int i=l; i<=r; i++) cnt[id[i]] = 0;
    		return ret;
    	}
    	if(b[l] + 1 <= b[r] - 1)
    		ret = mx[b[l] + 1][b[r] - 1];
    	for(int i=l; i<=min(n,b[l]*blk); i++) cnt[id[i]] = 0;
    	for(int i=(b[r] - 1) * blk + 1; i<=r; i++) cnt[id[i]] = 0;
    	for(int i=l; i<=min(n,b[l]*blk); i++) {
    		cnt[id[i]] ++;
    		ret = max(ret,cnt[id[i]]*a[i] + sum[b[r] - 1][id[i]] - sum[b[l]][id[i]]);
    	}
    	for(int i=(b[r]-1) * blk + 1; i<=r; i++) {
    		cnt[id[i]] ++;
    		ret = max(ret,cnt[id[i]]*a[i] + sum[b[r] - 1][id[i]] - sum[b[l]][id[i]]);
    	}
    	return ret;
    }
    int main() {
    	n = read,m = read;
    	blk = sqrt(n);
    	for(int i=1; i<=n; i++) a[i] = read,vet.push_back(a[i]);
    	sort(vet.begin(),vet.end());
    	vet.erase(unique(vet.begin(),vet.end()),vet.end());
    	int siz = vet.size();
    	for(int i=1; i<=n; i++) {
    		b[i] = (i - 1) / blk + 1;
    		id[i] = get(a[i]);
    		c[b[i]][id[i]] += a[i];
    	}
    	int lim = ceil(1.0 * n / blk);/// amt of the blks
    	for(int i=1; i<=lim; i++) {
    		for(int j = 1; j<=siz; j++) {
    			sum[i][j] = sum[i-1][j];
    			sum[i][j] += c[i][j];
    		}
    	}
    	/// pre init
    	for(int i=1; i<=lim; i++) pre(i);
    	Clear(cnt,0);
    	ll lastans = 0LL;
    	for(int i=1; i<=m; i++) {
    		ll l = read,r = read;
    		l = (l ^ lastans) % n + 1;
    		r = (r ^ lastans) % n + 1;
    		if(l > r) swap(l,r);
    		lastans = query(l,r);
    		cout << lastans << endl;
    	}
    	return 0;
    }
    /**
    5 5
    9 8 7 8 9
    0 1
    10 11
    9 9
    11 9
    16 19
    
    
    
    
    9
    8
    8
    16
    16
    
    **/
    

    在这个题的预处理过程中,写法参考求众数的时候的方法
    在这里插入图片描述

  • 相关阅读:
    HDU 1527 取石子游戏 (威佐夫博奕)
    HDU 1159 Common Subsequence (LCS)
    HDU 1160 FatMouse's Speed (LIS)
    HDU 2577 How to Type (DP)
    csu 1395: Timebomb (模拟)
    csu 1556: Jerry's trouble(大数取模)
    csu 1553: Good subsequence (最长连续子序列)
    csu 1548: Design road (三分)
    csu 1547: Rectangle (01背包)
    csu 1541: There is No Alternative(Kruskal 最小生成树)
  • 原文地址:https://www.cnblogs.com/PushyTao/p/15459812.html
Copyright © 2020-2023  润新知