zoukankan      html  css  js  c++  java
  • AT1218 たのしい家庭菜園

    AT1218 たのしい家庭菜園

    题目

    给定一个序列\(a\),你每次可以交换相邻两个元素,你需要通过一系列操作,使得\(a\)序列不严格单峰,求最小操作次数。

    思路

    首先,我们设一个\(1\sim n\)的排列,\(p_i\)表示\(a_i\)最终移动到了位置\(p_i\).

    则操作次数就是排列\(p\)的逆序对数量.简单证下就是将\(a_i\)移动到一号位,就会产生\(i-1\)个逆序对,\(i-1\)此操作,再考虑\(a_j\)移动到二号位,同理,所以,一次操作对应逆序对数量加一.

    然后贪心,从小到大枚举每一个\(a_i\),考虑它放在左边还是右边.

    假设我们左边\(1\sim l\),右边\(r\sim n\)已经放置,\(a_i\)要么放\(l+1\),要么放\(r-1\),对比一下两个方案对逆序对产生的贡献.

    不论放哪边,\(a_i\)\(1\sim n\), \(r\sim n\)产生的贡献都是一定的.

    区别就在于还没有放置的那些草,我们设集合\(S\)表示还没放的草的下标,对比下\(S\)中大于/小于\(i\)的元素数量即可决策,没有后效性,因此贪心是正确的.

    需要注意的是若存在\(i,j\ (i\neq j)\),使得\(a_i=a_j\).若某次操作中使得两个元素相邻了,我们并不需要交换它们,因为交换没有任何意义,所以,贪心的时候应当提前消除相同值的元素的影响.

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    #define int long long
    using namespace std;
    const int N = 3e5 + 10;
    int read() {
    	int re = 0;
    	char c = getchar();
    	bool negt = false;
    	while(c < '0' || c > '9')
    		negt |= (c == '-') , c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return negt ? -re : re;
    }
    struct TreeArray {
    	int n;
    	int a[N];
    	#define lowbit(_) ((_) & -(_))
    	void upd(int pos , int dat) {
    		for( ; pos <= n ; pos += lowbit(pos))a[pos] += dat;
    	}
    	int GetSum(int pos) {
    		int sum = 0;
    		for( ; pos ; pos -= lowbit(pos))sum += a[pos];
    		return sum;
    	}
    	int GetSum(int l , int r) {
    		return GetSum(r) - GetSum(l - 1);
    	}
    } a;
    
    int n;
    int h[N];
    struct Grass {
    	int h , id;
    } g[N];
    bool cmp(Grass a ,  Grass  b) {
    	return a.h != b.h ? (a.h < b.h) : (a.id > b.id);
    }
    signed main() {
    	a.n = n = read();
    	for(int i = 1 ; i <= n ; i++)
    		g[i].h = read() , g[i].id = i;
    	sort(g + 1 , g + n + 1 , cmp);
    	for(int i = 1 ; i <= n ; i++)
    		a.upd(i , 1);
    	long long ans = 0;
    	for(int l = 1 ; l <= n ; ) {
    		int r = l;
    		while(r <= n && g[r].h == g[l].h)a.upd(g[r].id , -1) , ++r;
    		for(int i = l ; i < r ; i++)
    			ans += min(a.GetSum(g[i].id - 1) , a.GetSum(g[i].id + 1 , n));
    		l = r;
    	}
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    uva 489 Hangman Judge(水题)
    中国海洋大学第四届朗讯杯高级组 Cash Cow(模拟)
    中国海洋大学第四届朗讯杯高级组 A 2718 Rocky(模拟)
    poj 1039 Pipe(叉乘。。。)
    CodeForces 135 B. Rectangle and Square(判断正方形和 矩形)
    poj 1265 Area( pick 定理 )
    poj 2031 Building a Space Station(prime )
    hdu 4502 吉哥系列故事——临时工计划(dp)
    拉格朗日插值
    [USACO18DEC]The Cow Gathering P
  • 原文地址:https://www.cnblogs.com/dream1024/p/15575529.html
Copyright © 2011-2022 走看看