BZOJ 1563 NOI2009 诗人小G 四边形不等式

50 篇文章 1 订阅
27 篇文章 0 订阅

题目大意:玩具装箱,然而指数变成了 p (p10)

首先我们需要证明决策单调
由于数死早,还是戳这里

知道决策单调之后怎么办呢?
由于是1D1D,所以不能分治了

每个决策点能决策的区间一定是连续的一段
并且随着决策点的右移 这个区间也在不断右移

g[j] 表示决策点 j 能贡献的最左侧的位置
然后我们开一个栈来维护当前存在贡献的贡献点
那么显然stack[i]的贡献区间是 [g[stack[i]],g[stack[i+1]]1]
每新来一个点,首先在栈中二分找到最优决策点
然后将所有满足
f[stack[top]]+W(stack[top],g[stack[top]])>f[i]+W(i,g[stack[top]])
的栈顶弹掉
然后二分找到最左侧的位置 pos 满足
f[stack[top]]+W(stack[top],pos)>f[i]+W(i,pos)
那么这个 pos 就是 g[i] ,如果能找到这个 pos ,就将 i <script type="math/tex" id="MathJax-Element-13">i</script>压栈

由于数字可能过大因此要用long double代替long long进行计算

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define LIMIT 1000000000000000000ll
using namespace std;
typedef long double ld;
int n,l,p;
int sum[M],g[M],stack[M],top;
ld f[M];
long double Slow_Power(long double x,int y)
{
    long double re=1;
    for(int i=1;i<=y;i++)
        re*=x;
    return re;
}
int Get_Len()
{
    static char s[40];
    scanf("%s",s+1);
    return strlen(s+1);
}
int Get_Pos(int x)
{
    int l=1,r=top;
    while(r-l>1)
    {
        int mid=l+r>>1;
        if( g[stack[mid]]<=x )
            l=mid;
        else
            r=mid;
    }
    return g[stack[r]]<=x?r:l;
}
ld F(int j,int i)
{
    return f[j]+Slow_Power(fabs(sum[i]-sum[j]+(i-j-1)-l),p);
}
int Get_G(int x,int y)
{
    int l=max(g[x],y)+1,r=n+1;
    while(r-l>1)
    {
        int mid=l+r>>1;
        if( F(y,mid) < F(x,mid) )
            r=mid;
        else
            l=mid;
    }
    if(l==r) return r;
    return F(y,l) < F(x,l) ? l : r ;
}
int main()
{
    int T,i;
    for(cin>>T;T;T--)
    {
        cin>>n>>l>>p;
        for(i=1;i<=n;i++)
            sum[i]=sum[i-1]+Get_Len();
        g[0]=1;stack[top=1]=0;
        for(i=1;i<=n;i++)
        {
            int pos=stack[Get_Pos(i)];
            f[i]=F(pos,i);
            while( g[stack[top]]>i && F(i,g[stack[top]]) < F(stack[top],g[stack[top]]) )
                stack[top--]=0;
            pos=Get_G(stack[top],i);
            if(pos!=n+1)
            {
                stack[++top]=i;
                g[i]=pos;
            }
        }
        if(f[n]-0.5>LIMIT)
            puts("Too hard to arrange");
        else
            cout<<(long long)(f[n]+0.5)<<endl;
        puts("--------------------");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值