hdu5009 Paint Pearls

版权声明:转载请注明出处 https://blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/81637186

链接

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

题解

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

猜你喜欢

转载自blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/81637186