题目描述
给出一个数列 P P P,把 P P P分为 K K K段, S i S_i Si
对于每一段编码位数 = 12 + A ( i ) ∗ B ( i ) =12+A(i)*B(i) =12+A(i)∗B(i)
A ( i ) A(i) A(i)表示该段有多少个数, B ( i ) B(i) B(i)表示该段中最大的数用二进制表示有多少位
题目解析
D P DP DP,设 f [ i ] f[i] f[i]表示编到第 i i i位的最小编码位数
因为每个 i i i作为一段的首位,所以可以从后往前推
对于每个 f [ i ] f[i] f[i]可以分为一段,则该段最长长度为 255 255 255,所以判断一下,不越界即可
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n,x;
int a[30005],f[30005];
int main()
{
freopen("coding.in","r",stdin);
freopen("coding.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
while(x)
{
a[i]++;
x>>=1;
}
}
for(int i=1;i<=n;i++)
f[i]=1e9;
for(int i=n;i>=1;i--)
{
f[i]=f[i+1]+12+a[i];
int maxn=a[i];
for(int j=i+2;j<=min(i+255,n+1);j++)
{
maxn=max(maxn,a[j-1]);
f[i]=min(f[i],f[j]+(j-i)*maxn+12);
}
}
printf("%d",f[1]);
return 0;
}