link

考虑DP。

设$h_i,c_i$为第$i$个骨牌的高度,推倒代价。

记$l_i$表示把$i$向左推,能推倒的最小的编号。

记$r_i$表示把$i$向右推,能推倒的最大的编号。

设$dp_i$表示推倒前$i$个骨牌的最小代价。

  1. 可以把$i$往左推: $dp_{l_i-1}+c_i$
  2. 可以把前面某一个$j$往右推使得能推倒$i$: $dp_{j-1}+c_j$。

于是,直接转移是$O(m^2)$的。

有一个结论: 若$j$始终满足$j\le i,r_j\ge i$,则随着$j$增加,$r_j$不增。

证明:

  1. r_i=i
  2. 若$i\le j\le r_i$则$r_i\ge r_j$
  3. 若$x$满足条件,则$r_x\ge i\ge j$,所有$\ge x$的$j$都满足$j\le r_x$。根据2得到结论。

所以单调栈一下就完事了。

至于$l_i$怎么处理,, 把当前不能被向左推推倒的编号扔进单调栈一下,,,$r_i$也一样的。

然后做完了。

/*
Author: QAQ-Automaton
LANG: C++
PROG: G.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %lld\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
#define inf 0x3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f3f
const double eps=1e-8;
const double pi=acos(-1.0);
template<class T>ll chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>ll chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
template<class T>ll dcmp(T a,T b){return a>b;}
template<ll *a>ll cmp_a(ll x,ll y){return a[x]<a[y];}
#define min mmin
#define max mmax
#define abs aabs
namespace io {
    const ll SIZE = (1 << 21) + 1;
    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; ll f, qr;
    // getchar
    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    // prll the remaining part
    inline void flush () {
        fwrite (obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
    // putchar
    inline void putc (char x) {
        *oS ++ = x;
        if (oS == oT) flush ();
    }
    // input a signed lleger
    inline bool read (signed &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;else if(c==EOF)return 0;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
        return 1;
    }

    inline bool read (long long &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;else if(c==EOF)return 0;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
        return 1;
    }
    inline bool read (char &x) {
        x=gc();
        return x!=EOF;
    }
    inline bool read(char *x){
        while((*x=gc())=='\n' || *x==' '||*x=='\r')if(*x==EOF)return 0;
        while(!(*x=='\n'||*x==' '||*x=='\r'))*(++x)=gc();
        *x=0;
        return 1;
    }
    template<typename A,typename ...B>
    inline bool read(A &x,B &...y){
        return read(x)&&read(y...);
    }
    // prll a signed lleger
    inline bool write (signed x) {
        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
        while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
        while (qr) putc (qu[qr --]);
        return 0;
    }

    inline bool write (long long x) {
        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
        while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
        while (qr) putc (qu[qr --]);
        return 0;
    }
    inline bool write (char x) {
        putc(x);
        return 0;
    }
    inline bool write(const char *x){
        while(*x){putc(*x);++x;}
        return 0;
    }
    inline bool write(char *x){
        while(*x){putc(*x);++x;}
        return 0;
    }
    template<typename A,typename ...B>
    inline bool write(A x,B ...y){
        return write(x)||write(y...);
    }
    //no need to call flush at the end manually!
    struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: read;
using io :: putc;
using io :: write;
ll n,m,k[250005];
vector<pii> blk[250005];
pii a[10000005],wstk[10000005],*wtop;
ll ls[10000005],rs[10000005],f[10000005],stk[10000005],*top;
void init(){
    ll x,y;
    read(n,m);
    for(ll i=1;i<=n;++i){
        read(k[i]);
        for(ll j=0;j<k[i];++j){
            read(x);
            blk[i].push_back(make_pair(x,0));
        }
        for(ll j=0;j<k[i];++j){
            read(blk[i][j].y);
        }
    }    
    read(n);
    m=0;
    for(ll w=1;w<=n;++w){
        read(x,y);
        for(auto i:blk[x]){
            a[++m]=i;
            a[m].y*=y;
        }
    }
    n=m;
}
ll solve(){
    top=stk;
    for(ll i=1;i<=n;++i){
        while(top!=stk && *top>i-a[i].x)--top;
        ls[i]=*top;
        *(++top)=i;
    }
    top=stk;
    for(ll i=n;i;--i){
        while(top!=stk && *top<i+a[i].x)--top;
        rs[i]=*top;
        *(++top)=i;
    }
    wtop=wstk;
    for(ll i=1;i<=n;++i){
        f[i]=f[ls[i]]+a[i].y;
        while(wtop!=wstk && wtop->y==i)--wtop;
        if(wtop!=wstk)chkmin(f[i],wtop->x);
        ll w=f[i-1]+a[i].y;
        while(wtop->y==rs[i] && wtop->x>w)--wtop;
        if(wtop==wstk || wtop->x>w)*(++wtop)=make_pair(w,rs[i]);
    }
//    for(ll i=1;i<=n;++i)write(a[i].x,' ',a[i].y,' ',ls[i],' ',rs[i],' ',f[i],'\n');
    return f[n];
}
int main(){
#ifdef QAQAutoMaton 
    freopen("G.in","r",stdin);
    freopen("G.out","w",stdout);
#endif
    init();
    write(solve(),'\n');
    return 0;
}

标签: DP, 单调栈

添加新评论