zoukankan      html  css  js  c++  java
  • AT4519[AGC032D]Rotation Sort【dp】

    正题

    题目链接:https://www.luogu.com.cn/problem/AT4519


    题目大意

    给出一个长度为\(n\)的排列,每次可以选择一个区间,然后花费\(A\)的代价向左旋转(最左边的丢到最右边)或者花费\(B\)的代价向右旋转。
    排升序序的最小花费。

    \(1\leq n\leq 5000\)


    解题思路

    相当于向右丢和向左丢。因为位置不固定非常麻烦,我们可以考虑统计那些顺序固定的。

    \(f_i\)表示做到第\(i\)个且第\(i\)个不动的最小花费,然后考虑\(f_j\)转移到\(f_i\)时的代价,那么显然我们要把中间数都变成在\(a_j\)\(a_i\)之间,所以把其中所有大于\(a_i\)的往右丢,小于\(a_j\)的往左丢。
    这样可以做到\(O(n^3)\)或者用数据结构做到\(O(n^2\log n)\)

    但是我们考虑到小于\(a_j\)的同时也是小于\(a_i\)的,如果我们把所有小于\(a_i\)的都往左丢,这样不会出现更小的答案,所以不会被统计到里面。

    这样就只和\(a_i\)有关了,倒序枚举\(j\)然后\(O(n^2)\)转移即可。

    用线段树可以做到\(O(n\log n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=5100;
    ll n,A,B,a[N],f[N];
    signed main()
    {
    	scanf("%lld%lld%lld",&n,&A,&B);
    	for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);
    	memset(f,0x3f,sizeof(f));
    	a[0]=-1;++n;a[n]=n;f[0]=0;
    	for(ll i=1;i<=n;i++){
    		ll up=0,dn=0;
    		for(ll j=i-1;j>=0;j--){
    			if(a[j]<a[i])f[i]=min(f[i],f[j]+up*A+dn*B);
    			if(a[j]>a[i])up++;else dn++;
    		}
    	}
    	printf("%lld\n",f[n]);
    }
    
  • 相关阅读:
    vue 中简单路由的实现
    Vue中对生命周期的理解
    内存泄漏
    前端工程化
    exports 和 module.exports 的区别
    Nodejs的url模块方法
    MongoDB 的获取和安装
    Anjular JS 的一些运用
    移动端vconsole调试
    安装fiddler时,电脑浏览器没网
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14446146.html
Copyright © 2011-2022 走看看