【JZOJ 5415】【NOIP2017提高A组集训10.22】公交运输

Description

城市中有一条长度为n的道路,每隔1的长度有一个公交车站,编号从0到n,学校在0号车站的位置。其中每个公交车站(除了n号车站)有两个属性ci和vi,代表从这个公交车站出发的公交车的性质。ci代表这个从i出发的公交车,相邻两个停靠站之间的距离。vi表示每坐1站的花费。
注意,一辆公交车出发后会向n号车站的方向行进。同时,一名乘客只能从起点站上车,但可以从任意停靠站下车。校庆志愿者小Z为了帮助校友查询有关城市交通费用的问题,想知道从0号车站(也就是学校)出发,到达每个公交车站的最小花费,于是他找到了你。

Solution

先按c的大小和%c余数分组,

带log的做法显然,就是维护一堆直线嘛,
这题看起来不能用斜率优化,但其实是可以用斜率优化的,

试想,对于同一组,它们前面的都可以到达后面的,
在最优的情况下,把这些直线按位置i排序,那么它们的vi都是增的,
证明显然:因为你前面的可以走到后面的嘛,既然你前面的vi大于你后面的,那么干嘛不先走到后面那个点,再用这个小一点的vi来往后走,

那么现在题目就变成了,每次在一堆直线中加入一个斜率比前面都要大的,怎么维护,

显然,斜率大前期可能优,但很快就不优了,到后面还优的一般都是斜率小的,
又因为我们每次是先删掉斜率比新加的大的,所以用一个栈来维护,
栈里的元素,斜率单调递减,每次查询就比较连续的两个,如果劣就弹栈,

但这样显然有错,就算保证斜率是单调的,也不能保证栈顶到栈底就是x越大越优,
所以在插入的时候,你就要判断一下交点的位置,这个画3条线的情况就可以看出来了,(懒)

复杂度: O(n10)

Code

#include 
#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define JS(q,w,I) ((q)*(I)+(w))
using namespace std;
const int N=1000500,INF=2147483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,mxc;
int c[N],va[N];
int f[N];
int za[11][11][2001];
int za1[11][11][2001];
int JA(int k,int b,int k1,int b1){return (b1-b)/(k-k1);}
int main()
{
    int q,w;
    read(n),read(mxc);
    fo(i,0,n-1)read(c[i]),read(va[i]),f[i+1]=INF;
    q=c[0];
    za[q][0][za[q][0][0]=1]=va[0];
    fo(i,1,n)
    {
        fo(j,1,mxc)
        {
            q=i%j;
            if(!za[j][q][0])continue;
            for(;za[j][q][0]>1&&JS(za[j][q][za[j][q][0]],za1[j][q][za[j][q][0]],i/j)
                >=JS(za[j][q][za[j][q][0]-1],za1[j][q][za[j][q][0]-1],i/j);za[j][q][0]--);
            f[i]=min(f[i],JS(za[j][q][za[j][q][0]],za1[j][q][za[j][q][0]],i/j));
        }
        if(f[i]==INF){printf("-1 ");continue;}
        printf("%d ",f[i]);
        if(i==n)break;
        q=c[i];
        w=i%c[i];
        for(;za[q][w][0]&&za[q][w][za[q][w][0]]>=va[i];za[q][w][0]--);
        for(;za[q][w][0]>1&&
        JA(za[q][w][za[q][w][0]],za1[q][w][za[q][w][0]],za[q][w][za[q][w][0]-1],za1[q][w][za[q][w][0]-1])<
        JA(za[q][w][za[q][w][0]],za1[q][w][za[q][w][0]],va[i],f[i]-(i/q)*va[i]);za[q][w][0]--);
        za[q][w][++za[q][w][0]]=va[i];
        za1[q][w][za[q][w][0]]=f[i]-(i/q)*va[i];
    }
    printf("\n");
    return 0;
}

你可能感兴趣的:(DP)