题目大意:玩具装箱,然而指数变成了p(p≤10)
首先我们需要证明决策单调
由于数死早,还是戳这里吧
知道决策单调之后怎么办呢?
由于是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压栈
由于数字可能过大因此要用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;
}
时间: 2024-10-14 01:01:58