• 19-11-06-&


    你&我处于这里……在一起?

    $$ ext{%%%Wearry}$$

    ZJ:

    一遇到Wearry的思维题就得×得够呛。

    考试心态炸裂,码上三个暴力然后就不知道该干啥了。

    现在就想敲自己。

    不要放弃一点点分!

    37
    Miemeng 20
    00:00:22
    0
    00:00:23
    0
    00:00:23
    20
    00:00:23

    摁 end 键就能找到我啦!

    UPD:

    ××晚上梦见自己省三是不是要死了???

    TJ:

    先改了下T2,觉得再不写博客就AFO了非常妙然后先写个。

    T2:

    考试根本没想法,($12$的数据范围意思就是$O(N!) sim O(1)$都……)

    一点提示都没有(主要是自己太菜啥都没想出来)

    首先应该转换题意。

    如果你真的想把中间的变成最大的,为什么不把小的放在左右两边呢?

    因为并没有规定最大值的位置。

    这样的转换(感性理解)是正确的。

    所以……

    $10\%$算法

    每次找区间最小值,然后比较它距离左右的距离,然后暴力向短的方向左右移。

    不要问我为什么$10\%$,此算法并没有考虑同等大小的数的优先级。

    $30\%$算法

    考虑区间里如果有两个最小值怎么办?

    从贪心的角度看,应该将距离左/右侧最小的进行移动。

    我们证明这种操作的正确性。

    1

    现在有左右两个相同小的值,它们之间的值全部比它们大所以就不具体画出了。

    那么我们就又有许多情况。

      右向左($B>A+k'$) 右向右($B<A+k'$)

    左向左                    

    $(A<B+k)$

    先让左向左会更优

    没有顺序的影响。

    两种操作顺序不影响答案

    左向右

    $(A>B+k)$

    有可能??

    先让右向右答案更优

    那么我们解简单不等式:

    当$A<B$时我们先将左向左移动更优。

    当$A>B$时我们先将右向右移动更优。

    得到$30$分

    #include <iostream>
    #include <cstring>
    #include <climits>
    #include <cstdio>
    // #include "debug.h"
    #define N 111111
    
    using namespace std;
    
    int len;
    int arr[N],ans=0;
    
    void dfs(int l,int r){
    	if(l==r) return ;
    	int minn=INT_MAX,id;
    	for(int i=l;i<=r;i++){
    		if( minn > arr[i]){
    			minn = arr[i];
    			id   = i;
    		}
    		else if( minn == arr[i] && min(r-id,id-l) > min(r-i,i-l)){
    			id = i;
    		}
    	}
    	if(r-id > id-l){
    		ans+=id-l;
    		for(int i=id;i>=l+1;i--)
    			arr[i]=arr[i-1];
    		arr[l]=minn;
    		dfs(l+1,r);
    	}
    	else{
    		ans+=r-id;
    		for(int i=id;i<=r-1;i++)
    			arr[i]=arr[i+1];
    		arr[r]=minn;
    		dfs(l,r-1);
    	}
    }
    int main(){
    #ifndef LOCAL
    	freopen("time.in" ,"r",stdin);
    	freopen("time.out","w",stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    	cin>>len;
    	for(int i=1;i<=len;i++)
    		cin>>arr[i];
    	dfs(1,len);
    	cout<<ans<<endl;
    }
    

    $100\%$算法

    我们已经在上面解决了许多的前趋问题,于是我们发现每次移动的答案贡献只有它向前/后比它大的块数,比它小的和等于它的全都会提前换到指定位置导致它没办法和它换(人家先占好坑了)。

    那么用个全职权值树状数组。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define N 111111
    
    using namespace std;
    
    int len;
    int arr[N];
    int pre[N],aft[N];
    int ans;
    namespace szsz{
    	int arr[N];
    	const int size=100010;
    	inline int lowbit(int x){
    		return x&(-x);
    	}
    	void add(int pos,int v){
    		while(pos<=size){
    			arr[pos]+=v;
    			pos+=lowbit(pos);
    		}
    	}
    	int query(int pos){
    		int res=0;
    		while(pos){
    			res+=arr[pos];
    			pos-=lowbit(pos);
    		}
    		return res;
    	}
    	void clear(){
    		memset(arr,0,sizeof arr);
    	}
    }
    int main(){
    #ifndef LOCAL
    	freopen("time.in" ,"r",stdin);
    	freopen("time.out","w",stdout);
    #endif
    	ios_base::sync_with_stdio(false);
    	cin>>len;
    	for(int i=1;i<=len;i++)
    		cin>>arr[i];
    	for(int i=1;i<=len;i++){
    		pre[i]=szsz::query(100000) - szsz::query(arr[i]);
    		szsz::add(arr[i],1);
    	}
    	szsz::clear();
    	for(int i=len;i>=1;i--){
    		aft[i]=szsz::query(100000) - szsz::query(arr[i]);
    		szsz::add(arr[i],1);
    	}
    	for(int i=1; i<=len; i++)
    		ans+=min(pre[i],aft[i]);
    	cout<<ans<<endl;
    }
    
  • 相关阅读:
    join()方法的使用
    synchronized关键字
    voliatle关键字
    一.线程概述
    NIO demo
    同步阻塞I/O
    Ubuntu16.04.1 安装Nginx
    垃圾收集
    如何从头开始安装 wordpress
    centos 6 安装 gnu c++ 等开发工具
  • 原文地址:https://www.cnblogs.com/kalginamiemeng/p/Exam20191106.html
Copyright © 2020-2023  润新知