斜率优化
HDU3507 Print Article
设 \(dp[i]\) 表示 \(1\sim i\) 的方式,转移就是同一段或者多一个,令 \(s[i]=\sum_{j=1}^i a[j]\) ,
……被多测打败了 /ll
Code
//Author: RingweEH
int X( int j ) { return s[j]; }
int Y( int j ) { return dp[j]+s[j]*s[j]; }
db slope( int t1,int t2 )
{ return (X(t2)!=X(t1)) ? (db)(Y(t2)-Y(t1))/(X(t2)-X(t1)) : LLONG_MAX; }
signed main()
{
//freopen( "exam.in","r",stdin );
while ( scanf("%lld%lld",&n,&m)!=EOF )
{
for ( int i=1; i<=n; i++ ) s[i]=s[i-1]+read();
head=tail=0; q[++tail]=0;
for ( int i=1; i<=n; i++ )
{
while ( head<tail && slope(q[head],q[head+1])<=2*s[i] ) head++;
dp[i]=dp[q[head]]+(s[i]-s[q[head]])*(s[i]-s[q[head]])+m;
while ( head<tail && slope(q[tail-1],q[tail])>=slope(q[tail-1],i) ) tail--;
q[++tail]=i;
}
printf("%lld\n",dp[n] );
s[0]=0; memset( dp,0,sizeof(int)*n );
}
return 0;
}
LOJ 10188 玩具装箱
Code
LOJ 10192 锯木厂选址
设 \(dp[i]\) 表示将第二个锯木厂放在 \(i\) 的最小费用。假设一开始全部移到了本来就有的那个厂,相当于用总费用换一部分到 \(j\) (枚举的第一个),再换一部分到 \(i\) 。对 \(d[i]\) 做后缀和,\(w[i]\) 做前缀和,把第一部分放到 \(j\) 就是少了 \(w[j]\times d[j]\) ;第二部分是 \((w[i]-w[j])\times d[i]\) 。那么式子就是
式子 \(w\) 抄成 \(d\) 了调一年 /fn
Code
LOJ10189 仓库建设
设 \(sp[i]=\sum_{j=1}^i p[j],s[i]=\sum_{j=1}^i p[j]\times x[j]\) ,那么有
Code
P2900 Land Acquisition G
考虑一块土地该怎么算。显然,对于一块地 \(x\) ,如果存在一个 \(y\) 的长宽均大于它,那么这块土地跟没有一样,排序加单调栈解决。
假设是按照长排序,那么此时留下的土地宽降序。显然在最优决策下,每组土地是连续的一段。方程就是
注意下那个重载的写法,PKUSCD1T1 就这么没得。
Code
//Author: RingweEH
const int N=2e5+10;
struct StrLand
{
int x,y;
bool operator < ( const StrLand tmp ) const { return (x^tmp.x) ? x<tmp.x : y<tmp.y; }
}a[N],sta[N];
int n,top=0,q[N],head,tail,dp[N];
void Init()
{
sort( a+1,a+1+n ); sta[++top]=a[1];
for ( int i=2; i<=n; i++ )
{
while ( top && sta[top].y<=a[i].y ) top--;
sta[++top]=a[i];
}
n=top;
}
//K=l[i] X=-w[j+1] Y=dp[j]
int X( int j ) { return -sta[j+1].y; }
int Y( int j ) { return dp[j]; }
db slope( int i,int j ) { return (db)(Y(j)-Y(i))/(X(j)-X(i)); }
signed main()
{
//freopen( "exam.in","r",stdin );
n=read();
for ( int i=1; i<=n; i++ ) a[i].x=read(),a[i].y=read();
Init(); head=tail=1; q[1]=0;
for ( int i=1,j; i<=n; i++ )
{
while ( head<tail && slope(q[head],q[head+1])<=1.0*sta[i].x ) head++;
j=q[head]; dp[i]=dp[j]+sta[j+1].y*sta[i].x;
while ( head<tail && slope(q[tail-1],q[tail])>=slope(q[tail],i) ) tail--;
q[++tail]=i;
}
printf("%lld\n",dp[n] );
return 0;
}
LOJ10190 特别行动队
设 \(s[i]=\sum_{j=1}^i x[j]\)
Code
UOJ104 Split the sequence
设 \(s[i]=\sum_{j=1}^i a[j]\) ,有简单DP:
注意到这个式子只和 \(dp[][k-1]\) 有关,所以可以跑 \(K\) 次斜率优化。
Code
//Author: RingweEH
//K=-s[i] X=s[j] Y=g[j]-s[j]^2
const int N=1e5+10,INF=1e18;
int n,k,s[N],f[N],g[N],head,tail,q[N],path[N][210];
int X( int j ) { return s[j]; }
int Y( int j ) { return g[j]-s[j]*s[j]; }
db slope( int i,int j )
{ return (X(j)^X(i)) ? (db)(Y(j)-Y(i))/(X(j)-X(i)) : INF; }
signed main()
{
//freopen( "exam.in","r",stdin );
n=read(); k=read();
for ( int i=1; i<=n; i++ ) s[i]=s[i-1]+read();
for ( int cas=1; cas<=k; cas++ )
{
head=tail=0; q[0]=0;
for ( int i=1; i<=n; i++ )
{
while ( head<tail && slope(q[head],q[head+1])>=-s[i] ) head++;
int j=q[head]; f[i]=g[j]+s[j]*(s[i]-s[j]); path[i][cas]=j;
while ( head<tail && slope(q[tail-1],q[tail])<=slope(q[tail],i) ) tail--;
q[++tail]=i;
}
for ( int i=1; i<=n; i++ ) g[i]=f[i],f[i]=0;
}
printf("%lld\n",g[n] ); int nw=n;
for ( int i=k; i>=1; i-- ) printf("%lld ",path[nw][i] ),nw=path[nw][i];
return 0;
}
BZOJ3437 小P的牧场
这真的不是仓库建设简化版……?/xia
hoho!改了改输入过了 /px
Code
//Author: RingweEH
int X( int j ) { return sp[j]; }
int Y( int j ) { return dp[j]+s[j]; }
db slope( int t1,int t2 ) { return (db)(Y(t2)-Y(t1))/(X(t2)-X(t1)); }
signed main()
{
//freopen( "exam.in","r",stdin );
n=read();
for ( int i=1; i<=n; i++ ) x[i]=i-1;
for ( int i=1; i<=n; i++ ) c[i]=read();
for ( int i=1; i<=n; i++ ) p[i]=read();
sp[0]=s[0]=0;
for ( int i=1; i<=n; i++ ) sp[i]=sp[i-1]+p[i],s[i]=s[i-1]+p[i]*x[i];
head=tail=1,q[1]=0;
for ( int i=1,j; i<=n; i++ )
{
while ( head<tail && slope(q[head],q[head+1])<=x[i] ) head++; j=q[head];
dp[i]=dp[j]+x[i]*(sp[i]-sp[j])-(s[i]-s[j])+c[i];
while ( head<tail && slope(q[tail-1],q[tail])>=slope(q[tail],i) ) tail--;
q[++tail]=i;
}
printf("%lld\n",dp[n] );
return 0;
}
LOJ2035 征途
方差 \(s^2=\dfrac{\sum (x-X)^2}{m}\) ,所以
也就是说最小化 \(\sum x^2\) 即可。设 \(dp[i][k]\) 表示 \(1\sim i\) 用 \(k\) 天走完的最小代价。
K=2s[i] X=s[j] Y=g[j]+s[j]^2
和之前一样也是转移只和 \(k\) 相关的 DP ,直接暴力跑 \(m\) 次,\(O(nm)\) 的复杂度可以接受。
ps:题目长得很像扶苏那道忘情,大概WQS还能更优一点。

浙公网安备 33010602011771号