HDU 4570 Multi-bit Trie 解题报告

解决复杂数列分段问题的动态规划算法
本文详细解析了一个使用动态规划求解数列分段最小空间消耗的问题,通过简化题意和状态转移方程,实现了一种高效的算法解决方案。文中包括实例分析、代码实现及溢出判断细节,旨在提供一种易于理解且实用的编程技巧。

题目

比赛

题意:

这道题最难的就是题意了可怜

我们根据样例YY出来简化的题意:给出一个长度为n的数列,将其分成若干段,要求最小,其中ai是每一段数列的第一项,bi是每一段的长度,l为将数列分成l段。

比如样例:n=7,A={1 2 4 4 5 4 3},将其分成1 2 4| 4 5| 4| 3,则其所用空间为1*2^3+4*2^2+4*2^1+3*2^1=38,而如果分成1 2| 4 4 5| 4 3,则其所用空间为1*2^2+4*2^3+4*2^2=52,比38大。

因为n最大才64,所以就变成一道O(n^2)水水的DP题,状态转移方程:dp[i]=min{dp[j]+arr[i]*2^(i-j),j<i}

中间要注意一下溢出的判断。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
#define EPS 1e-5
using namespace std;
int num[10];
unsigned LL two[64];
unsigned LL arr[100];
unsigned LL dp[100];
int main()
{
    //freopen("/home/moor/Code/input.txt","r",stdin);
    two[0]=1;
    double top=((LL)1)<<62;
    top*=4;
    top-=1;
    for(int i=1;i<64;++i)
        two[i]=two[i-1]*2;
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;++i)    cin>>arr[i];
        memset(dp,0,sizeof(dp));
        for(int i=0;i<n;++i)
            for(int j=i+1;j<=n;++j)
            {
                if(j-i>=64) continue;
                unsigned LL tmp=two[j-i]*arr[i];
                if((double)two[j-i]*arr[i]-top>-EPS||(double)dp[i]+tmp-top>-EPS)    continue;
                if(dp[j]==0||dp[j]>dp[i]+tmp)
                    dp[j]=dp[i]+tmp;
            }
        cout<<dp[n]<<'\n';
    }
    return 0;
}


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值