BZOJ 2726 SDOI2012 任务安排

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/82694222

Problem

BZOJ

Solution

不难设出一个不怎么样的状态f[i][j]表示前i个分j段的最小代价

f [ i ] [ j ] = min ( f [ k ] [ j 1 ] + ( S j + s t [ i ] ) ( s f [ i ] s f [ k ] ) )

考虑未来费用优化,多分一段相当于后面所有段都加上S×费用

f [ i ] = min ( f [ j ] + s t [ i ] ( s f [ i ] s f [ j ] ) + S ( s f [ n ] s f [ j ] ) )

f [ i ] = s t [ i ] + s f [ i ] + S s f [ n ] + min ( f [ j ] s t [ i ] s f [ j ] S s f [ j ] ) )

时间复杂度 O ( n 2 )

发现不知道怎么单调队列,所以试试考虑斜率优化,若i从j转移比从k转移要优,则有:

f [ j ] f [ k ] + s t [ i ] ( s f [ k ] s f [ j ] ) + S ( s f [ k ] s f [ j ] ) < 0

f [ j ] f [ k ] < ( s t [ i ] + S ) ( s f [ j ] s f [ k ] )

f [ j ] f [ k ] s f [ j ] s f [ k ] < s t [ i ] + S

维护一个下凸包。又由于st[i]+s不一定单调,所以不能用单调队列,而是在维护好的凸包上二分。

注意特判sf[j]和sf[k]相等的时候,f小的更优秀。不过好像写的代码不同也有所不同,不然两种都试一下吧。

时间复杂度 O ( n log n )

Code

#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=1000010;
const double INF=1e20;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,s,tp,st[maxn],sf[maxn],stk[maxn];
ll f[maxn];
double slope(int j,int k)
{
    if(sf[j]==sf[k]) return f[j]<f[k]?INF:-INF;
    return 1.0*(f[j]-f[k])/(sf[j]-sf[k]);
}
int find(int k)
{
    int l=1,r=tp,m,res=1;
    while(l<=r)
    {
        m=(l+r)>>1;
        if(slope(stk[m-1],stk[m])<=k) res=m,l=m+1;
        else r=m-1;
    }
    return stk[res];
}
int main()
{
    read(n);read(s);
    for(rg int i=1;i<=n;i++)
    {
        read(st[i]);st[i]+=st[i-1];
        read(sf[i]);sf[i]+=sf[i-1];
    }
    stk[++tp]=0;
    for(rg int i=1;i<=n;i++)
    {
        int k=find(st[i]+s);
        f[i]=f[k]+(ll)st[i]*(sf[i]-sf[k])+(ll)s*(sf[n]-sf[k]);
        while(tp>1&&slope(stk[tp-1],stk[tp])>=slope(stk[tp],i)) tp--;
        stk[++tp]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/82694222