zoukankan      html  css  js  c++  java
  • [BalticOI 2004]Sequence

    非常棒的思维题!!

    半天都做不起,我咋这么菜……

    一、

    递增序列将每位-i就变成了非递减序列

    于是我们将(a_i-i),最后将答案(+i)变成了求非递减序列

    二、

    考虑初中数学题

    (|x-a|+|x-b|)的最小值,显然(xin[a,b](a<=b))时最小

    同理对于一个序列,我们只要找到其中位数即是最小答案(偶数位的中位数为中间两个数的平均数,但中间两个数区间内的数都可以,我们默认选较后面那位)

    三、

    尝试找到一种区间的划分,使得每一段区间的中位数呈非递减序列(这样就找到一组最优解了)

    每次进一个新元素的时候,自己成一个区间,如果比末尾的区间的中位数就合并两区间,重新找中位数

    四、

    需要支持插入+合并动态维护区间中位数的数据结构,用左偏树(可并堆)大根堆实现,每次合并后,若堆的大小太大就合并左右儿子(弹掉最大值),最后每个堆的根节点就是中位数

    我咋这么菜……

    这篇题解解法非常神奇

    只可意会不可言传!贪心乱搞

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e6+4;
    int n,m,dis[N],a[N],ed[N],rt[N],sz[N],ch[N][2];
    #define lc ch[p][0]
    #define rc ch[p][1]
    int merge(int p,int x){//大根堆 
    	if(!p||!x)return p|x;
    	if(a[p]<a[x])p^=x^=p^=x;
    	rc=merge(rc,x);
    	if(dis[lc]<dis[rc])lc^=rc^=lc^=rc;
    	dis[p]=dis[rc]+1;
    	sz[p]=sz[lc]+sz[rc]+1;
    	return p;
    }
    inline void adjust(){
    	static int p;
    	while((ed[m]-ed[m-1]+1>>1)<sz[p=rt[m]])
    		rt[m]=merge(lc,rc);
    }
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++){
    		a[i]=read()-i;
    		m++;ed[m]=rt[m]=i;sz[i]=1;
    		while(a[rt[m-1]]>a[rt[m]]){
    			rt[m-1]=merge(rt[m-1],rt[m]);
    			ed[m-1]=ed[m];
    			m--;
    			adjust();
    		}
    	}
    	long long ans=0;
    	for(int i=1,j=1;i<=m;i++)
    		for(;j<=ed[i];j++)
    			ans+=abs(a[j]-a[rt[i]]);
    	cout<<ans<<"
    ";
    	for(int i=1,j=1;i<=m;i++)
    		for(;j<=ed[i];j++)
    			cout<<a[rt[i]]+j<<" ";
    	return (0-0);
    }
    

    题解代码

    #include <bits/stdc++.h>
    using namespace std;
    inline int read() {
      static int ch, x;
      while (isspace(ch = getchar())) {}
      x = ch ^ 48;
      while (isdigit(ch = getchar())) x = (((x << 2) + x) << 1) + (ch ^ 48);
      return x;
    }
    #define MAXN 1000010
    int a[MAXN], b[MAXN];
    priority_queue<int> q;
    int main() {
      const int &n = read();
      long long ans = 0;
      for (int i = 1; i <= n; ++i) {
        a[i] = read() - i;
        q.push(a[i]);
        if (q.top() > a[i]) {
          q.pop();
          q.push(a[i]);
        }
        b[i] = q.top();
      }
      for (int i = n; i; --i) {
        ans += abs(a[i] - b[i]);
        b[i - 1] = min(b[i - 1], b[i]);
      }
      ios::sync_with_stdio(false);
      cout.tie(nullptr);
      cout << ans << '
    ';
      for (int i = 1; i <= n; ++i) {
        cout << (b[i] + i) << ' ';
      }
      return 0;
    }
    
  • 相关阅读:
    ESP8266简单几步建立服务器
    SVM推导
    标准的最大margin问题
    switch用法
    vecor预分配内存溢出2
    vector预分配空间溢出
    [面试编程题]算法基础-字符移位
    [面试编程题1]构造回文
    一天学完UFLDL
    神经网络中的XOR问题
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12599869.html
Copyright © 2011-2022 走看看