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;
}


你可能感兴趣的:(HDU 4570 Multi-bit Trie 解题报告)