hdu5009 Paint Pearls

链接

http://acm.hdu.edu.cn/showproblem.php?pid=5009

题解

乱搞题
fi=min{fj1+num2(j,i)} f i = m i n { f j − 1 + n u m 2 ( j , i ) }
咋优化?
看着像斜率优化,但问题是凸壳会变啊,难道用平衡树维护吗?我反正不想写
那只好瞎搞搞了
看这个:
2323232323232323232323
显然我从一个位置往前枚举的时候, num(j,i) n u m ( j , i ) 总是不变的,但是 f[j1] f [ j − 1 ] 在变小,所以我应该取 num n u m 相同的里面最往前的一个
我在进行枚举的时候,如果发现往前前进一步时 num(j,i) n u m ( j , i ) 却不变,那么这个元素的存在就是没意义的,我可以直接删掉,这个可以用一个双向链表来实现,而且当我的 num(j,i) n u m ( j , i ) 大于 N N 时,我就没必要枚举下去了
时间复杂度 O(NN) O ( N N ) ,这里的事件复杂度是指最劣的情况,即每个数字都不相同

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#include <cstdlib>
#define maxn 50010
#define ll_inf (1ll<<60)
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
using namespace std;
ll f[maxn], N, a[maxn], M, vis[maxn], tmp[maxn], pre[maxn], nex[maxn], flag, sqr[maxn];
ll read(ll x=0)
{
    char c, f=1;
    for(c=getchar();!isdigit(c) and c^-1;c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-48;
    return f*x;
}
bool init()
{
    ll i, t=0;
    cl(f,0);
    N=read();
    if(!N)return 0;
    for(i=1;i<=N;i++)tmp[i]=a[i]=read();
    sort(tmp+1,tmp+N+1);
    for(i=1;i<=N;i++)if(tmp[i]!=tmp[i-1])flag++;
    for(i=1;i<=N;i++)a[i]=lower_bound(tmp+1,tmp+N+1,a[i])-tmp;
    for(i=1;i<=N;i++)if(a[i]!=a[i-1])a[++t]=a[i];
    for(i=1;i<=N;i++)sqr[i]=i*i;
    N=t;
    cl(vis,0);
    return 1;
}
void dp()
{
    ll i, j, cost, pos;
    pre[1]=0;
    for(i=1;i<=N;i++)
    {
        cost=0;
        f[i]=ll_inf;
        pre[i]=i-1, nex[i-1]=i;

            for(j=i;j and sqr[cost]<=i;j=pre[j])
            {
                if(vis[a[j]]!=i)cost++, vis[a[j]]=i;
                else pre[nex[j]]=pre[j], nex[pre[j]]=nex[j];
                f[i]=min(f[i],sqr[cost]+f[pre[j]]);
            }
    }
    printf("%lld\n",f[N]);
}
int main()
{
    while(init())dp();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值