• CF 13C Sequence


    这是道双倍经验题,做完可以做Luogu P4597

    01

    ( exttt{离散化+滚动数组})

    Idea

    (dp[i][j])表示前i个数以(a[j])为结尾的满足要求的最少的操作,可是题目给的最大数是(10^9),二维数组的(j)元素不可能开这么大,所以需要离散化一下,改成前i个数以第(j)个数为结尾的满足要求的最少的操作。

    (dp[i][j]=min(dp[i][j], ext{第i-1个位置前j个数的最小操作}+abs(b[j]-a[i]))) (b)数组是原来输入的(a)数组排好序且离散化之后的数组

    因为(b)数组是从小到大排好序的,所以在第(i)个位置时第(j)个数肯定比(i-1)个位置的前j个数要大。

    最后(dp[5000][5000])也不能存下,那么这个二维数组就要滚一下了。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<string>
    #include<queue>
    #define ll long long
    #define maxn 100001
    #define mod 998244353
    #define eps 1e-6
    #define pi acos(-1.0)
    #define de(x) ((x)*(x))
    using namespace std; 
    inline int read(){
        int x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    const ll inf=1ll<<62;
    ll dp[2][5007],a[5007],b[5007];
    int main(){
    	ll n=read();
        for(ll i=1;i<=n;i++){
        	a[i]=read();
            b[i]=a[i];
        }
        sort(b+1,b+n+1);
        ll tot=unique(b+1,b+n+1)-b-1;//离散化
        dp[1][1]=inf;
        for(ll i=1;i<=tot;i++){
            dp[1&1][i]=fabs(b[i]-a[1]);
            dp[2&1][i]=inf;
        }
        for(ll i=2;i<=n;i++){
        	ll minn=inf;
            for(ll j=1;j<=tot;j++){
                minn=min(minn,dp[(i-1)&1][j]);//取上一个位置中前j颗不同高度的树中花费最小
                dp[i&1][j]=min(dp[i&1][j],minn+abs(b[j]-a[i]));//当前位置等于上一个位置中前j颗树花费最小+这个位置是第j颗树的花费
            }
        	for(ll j=1;j<=tot;j++) dp[(i+1)&1][j]=inf;
        }
    	ll ans=inf;
        for(ll i=1;i<=tot;i++) ans=min(ans,dp[n&1][i]);//取最后一个位置是第j颗树是花费最小
        printf("%lld",ans);
        return 0;
    }
    

    02

    考虑(DP)

    Idea

    (dp[i][j])表示前(i)个已经符合要求,而且最大数不大于原序列第(j)个元素最小需要的代价。
    那么我们可以得出转移方程(dp[i][j]=min(dp[i][j−1],dp[i−1][j]+abs(a[i]−c[j]))

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<string>
    #include<queue>
    #define ll long long
    #define maxn 100001
    #define mod 998244353
    #define eps 1e-6
    #define pi acos(-1.0)
    #define de(x) ((x)*(x))
    using namespace std; 
    inline ll read(){
        ll x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    const ll inf=1ll<<62;
    ll ans=inf;
    ll a[maxn],c[maxn],dp[2][maxn];
    int main(){
    	int n; scanf("%d",&n);
    	for(int i=1;i<=n;i++) a[i]=read(),c[i]=a[i];
    	sort(&c[1],&c[n+1]);
    	memset(dp,127,sizeof dp);
    	for(int i=1;i<=n;i++) dp[0][i]=0;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++)
    			dp[1][j]=min(dp[1][j-1],dp[0][j]+abs(a[i]-c[j]));
    		swap(dp[1],dp[0]);
    	}
    	for(int i=1;i<=n;i++) ans=min(ans,dp[0][i]);
    	printf("%I64d",ans);
        return 0;
    }
    

    (P.S: ext{这个方法过不了CF原网站的#8})

    DP优化

    排完序后发现,每个数的更换值都是最小的.
    那么有(dp)方程如下

    [dp[j]=abs(a[i]-a[j]); ]

    [dp[j]=min(dp[j],dp[j-1]); ]

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<string>
    #include<queue>
    #define ll long long
    #define maxn 5005
    #define inf 2147483647
    #define mod 998244353
    #define eps 1e-6
    #define pi acos(-1.0)
    #define de(x) ((x)*(x))
    using namespace std; 
    inline ll read(){
        ll x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    ll a[maxn],c[maxn],dp[maxn];
    int main(){
    	int n; scanf("%d",&n);
    	for(int i=1;i<=n;i++) a[i]=read(),c[i]=a[i];
    	sort(c+1,c+n+1);
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++){
    		dp[j]+=abs(a[i]-c[j]);
    		if(j>1) dp[j]=min(dp[j],dp[j-1]);
    	}
    	printf("%I64d",dp[n]);
        return 0;
    }//洛谷上用时4+ s,CF上用时342 ms
    

    03

    用堆写
    证明请看(我不会严格证明)

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<string>
    #include<queue>
    #define ll long long
    #define maxn 500005
    #define inf 2147483647
    #define mod 998244353
    #define eps 1e-6
    #define pi acos(-1.0)
    #define de(x) ((x)*(x))
    using namespace std; 
    inline int read(){
        int x=0,f=1; char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    priority_queue<int>q;
    ll ans;
    int main(){
    	int n=read();
    	for(int i=1;i<=n;i++){
    		int x=read();
    		q.push(x);
    		if(q.top()>x){
    			ans+=q.top()-x;
    			q.pop();
    			q.push(x);
    		}
    	}
    	printf("%lld",ans);
        return 0;
    }
    
  • 相关阅读:
    一些小姿势
    <学习笔记>《具体数学》
    【react】报错Need at least a key or a value or a label (only for OptGroup) for [object Object]
    Calibration Checkerboard Collection
    华为云如何建表并创建作业定时调度抽取数据
    HIVE SQL教程
    postgresql 教程
    PC机启用了fiddler代理,在手机或其它机器上连接该代理,无法抓包
    Unity3d的Scroll View组件不能滑动到底的解决方式
    Unity3d让GridLayoutGroup按照子物体的数量自动调整宽高
  • 原文地址:https://www.cnblogs.com/cbyyc/p/11475068.html
Copyright © 2020-2023  润新知