• 请客


    题意:

    给出一个长度为 n (<=100000) 的序列,有q次操作,每次操作将最大的K个数取出来求和,然后将这K个数减1,再放回序列,求最后的答案。

    题解:

    不难想首先将序列从小到大排序,从最后取出K个数,然后区间求和,区间减1,可以发现很容易保证这个序列的单调性。

    比如n = 6 K = 2 序列为 1 2 3 4 4 5 那么就应该修改成这样 1 2 3 3 4 4,那么就应该找出K个数中最小的那个数的前驱后继。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define LL long long
    const int N = 1e5 + 7;
    LL sum[N << 2], lz[N << 2], ans, mif[N << 2];
    int n, ai[N], K, q;
    
    #define mid (l + r >> 1)
    #define lson o << 1, l, mid
    #define rson o << 1 | 1, mid + 1, r
    
    void build (int o, int l, int r)
    {
    	if (l == r) 
    	{
    		sum[o] = ai[l];
    		return;
    	}
    	build(lson);
    	build(rson);
    	sum[o] = sum[o << 1] + sum[o << 1 | 1];
    }
    
    void pushdown (int o, int l, int r)
    {
    	sum[o << 1] += (mid - l + 1) * lz[o];
    	mif[o << 1] += (mid - l + 1) * lz[o];
    	lz[o << 1] += lz[o];
    	sum[o << 1 | 1] += (r - mid) * lz[o];
    	mif[o << 1 | 1] += (r - mid) * lz[o];
    	lz[o << 1 | 1] += lz[o];
    	lz[o] = 0;
    }
    
    void update (int o, int l, int r, int L, int R, int x)
    {
    	if (l == L && r == R) 
    	{
    		lz[o] += x;
    		mif[o] += (R - L + 1) * x;
    		sum[o] += (R - L + 1) * x;
    		return;
    	}
    	pushdown(o, l, r);
    	if (R <= mid) update(lson, L, R, x);
    	else if (L > mid) update(rson, L, R, x);
    	else update(lson, L, mid, x), update(rson, mid + 1, R, x);
    	sum[o] = sum[o << 1] + sum[o << 1 | 1];
    	mif[o] = mif[o << 1] + mif[o << 1 | 1];
    }
    
    LL query (int o, int l, int r, int L, int R)
    {
    	if (l == L && r == R) return sum[o];
    	pushdown(o, l, r);
    	if (R <= mid) return query (lson, L, R);
    	else if (L > mid) return query (rson, L, R);
    	else return query (lson, L, mid) + query (rson, mid + 1, R);
    }
    
    int lazy (int o, int l, int r, int x)
    {
    	if (l == r && l == x) return mif[o];
    	pushdown (o, l, r);
    	if (x <= mid) return lazy (lson, x);
    	else if (x > mid) return lazy (rson, x);
    }
    
    int find (int x)
    {
    	int l = 1, r = n;
    	while (l < r)
    	{
    		if (ai[mid] + lazy(1, 1, n, mid) >= x) r = mid;
    		else l = mid + 1;
    	}
    	return l;
    }
    
    int main () 
    {
    	scanf ("%d", &n);
    	for (int i = 1; i <= n; ++i) scanf ("%d", &ai[i]);
    	sort (ai + 1, ai + 1 + n);
    	build (1, 1, n);
    	scanf ("%d", &q);
    	while (q--)
    	{
    		scanf ("%d", &K);
    		int w = ai[n - K + 1] + lazy(1, 1, n, n - K + 1);
    		int x = find (w), y = find (w + 1);
    		if (ai[x] + lazy(1, 1, n, x) != ai[y] + lazy(1, 1, n, y))
    		{
    			ans += query (1, 1, n, x, x + K - n + y - 2);
    			ans += query (1, 1, n, y, n);
    			update (1, 1, n, x, x + K - n + y - 2, -1);
    			update (1, 1, n, y, n, -1);
    		}
    		else 
    		{
    			ans += query (1, 1, n, x, x + K - 1);
    			update (1, 1, n, x, x + K - 1, -1);
    		}
    	}
    	cout << ans << endl;
    	return 0;
    }
    

      

    总结:

    善于观察因为只减1,很容易就保证了序列的单调性呀~

  • 相关阅读:
    ASP.NET MVC请求处理管道生命周期的19个关键环节(13-19)
    ASP.NET MVC请求处理管道生命周期的19个关键环节(7-12)
    ASP.NET MVC请求处理管道生命周期的19个关键环节(1-6)
    关于领域模型
    WebForm和MVC的一些知识(转)
    抽象工厂
    SCP,scp linux2台机器之间如何传输文件
    mysql卸载(windows)【转】
    (5.2.3)配置服务器参数——服务器性能估算
    Windows命令行使用FTP
  • 原文地址:https://www.cnblogs.com/xgtao/p/6018812.html
Copyright © 2020-2023  润新知