动态dp坑爹记录。。。。常数巨大

最近在学个玄学东西,动态dp。在这里稍微记录一下

抛个序列上的动态dp题(树上的还不怎么会写,太玄学了。。。)

带单点修改的最大字段和

普通的状态转移嘛。。很简单

f[i]=max(f[i-1]+a[i],a[i])

g[i]=max(g[i-1],f[i])

动态dp这玩意是构造矩阵嘛。。然后把各种转移玄学的改成(乘法???)运算,这里的(乘法)必须满足结合律

可这玩意咋构造矩阵呢。。。

大家应该都知道斐波那契数列矩阵构造,很简单

\begin{bmatrix} 1 &1 \\ 1 &0 \end{bmatrix}\begin{bmatrix} f[i-1] \\ f[i-2] \end{bmatrix} = \begin{bmatrix} f[i]\\ f[i-1] \end{bmatrix}

可这玩意是f[i]=f[i-1]+f[i-2]有加法乘法,,,,这里来个max什么鬼。。我们把这个式子改写一下

f[i]=max(f[i-1]+a[i],a[i])=a[i]+max(f[i-1],0)

这玩意是啥?分配律!!!

大家都应该知道矩阵乘法满足结合律,为啥满足结合律呢?

因为有a*(b+c)=a*b+a*c 乘法对加法满足分配律

那么a+max(b,c)=max(a+b,a+c)加法对max/min这玩意也有分配律对不???对的!!

我们都知道矩阵乘法运算规则C[i][j]=\sum A[i][k]+B[k][j]

既然普通的矩阵乘法是两个两个乘再全部加起来,那我们可不可以C[i][j]=max(A[i][k]+B[k][j])两个两个加起来再取max!!

这玩意是满足结合律的!!

好了,我们这回可以改写一下那个状态转移方程了

f[i]=max(f[i-1]+a[i],a[i])

g[i]=max(g[i-1],f[i])=max(g[i-1],f[i-1]+a[i],a[i])

尝试利用C[i][j]=max(A[i][k]+B[k][j])构造矩阵!

\begin{bmatrix} a[i] & -inf & a[i]\\ a[i] & 0 &a[i] \\ -inf & -inf &0 \end{bmatrix}\begin{bmatrix} f[i-1]\\ g[i-1]\\ 0 \end{bmatrix} = \begin{bmatrix} f[i]\\ g[i]\\ 0 \end{bmatrix}

完美对不对!!!

然后有了这玩意,我们该怎么做呢?

观察一下,对于左边那个矩阵,他有个a[i] ,我们是不是可以对于每一个数字都创建该个这个矩阵,然后对于每个询问[l,r]我们是不是可以把区间内每个矩阵做一遍乘法,然后再乘一遍\begin{bmatrix} f[0]\\ g[0]\\ 0 \end{bmatrix}答案是不是就出来了,记住这里的f[0]=-inf,g[0]=-inf

到这里大功告成!!!

贴一遍代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=2e5+10;
struct mat{
    int n,m;
    int** A;
    inline mat():n(0),m(0){}
    inline void setsize(int sn,int sm){
        n=sn,m=sm;
        A=new int*[n];
        for(register int i=0;i<n;i++){
            A[i]=new int[m];
            for(register int j=0;j<m;j++){
                A[i][j]=-inf;
            }
        }
    }
    inline mat operator * (const mat& other)const{
        mat ret;
        ret.setsize(n,other.m);
        for(register int i=0;i<n;i++){
            for(register int j=0;j<other.m;j++){
                for(register int k=0;k<m;k++){
                    ret.A[i][j]=max(ret.A[i][j],A[i][k]+other.A[k][j]);
                }
            }
        }
        return ret;
    }
    inline mat operator *= (const mat& other){
        (*this)=(*this)*other;
        return (*this);
    }
};
inline void changedata(mat& d,int v){
    d.A[0][0]=v,d.A[0][1]=-inf,d.A[0][2]=v;
    d.A[1][0]=v,d.A[1][1]=0,d.A[1][2]=v;
    d.A[2][0]=-inf,d.A[2][1]=-inf,d.A[2][2]=0;
}
mat lstres;
int n,q;
struct segtree{
    mat c[maxn<<2];
    segtree(){
        for(register int i=0;i<maxn;i++){
            c[i].setsize(3,3);
        }
    }
    inline int lson(int k){
        return k<<1;
    }
    inline int rson(int k){
        return k<<1|1;
    }
    void change(int k,int l,int r,int p,int v){
        if(l==r){
            changedata(c[k],v);
            return;
        }
        int mid=(l+r)>>1;
        if(p<=mid){
            change(lson(k),l,mid,p,v);
        }else{
            change(rson(k),mid+1,r,p,v);
        }
        c[k]=c[lson(k)]*c[rson(k)];
    }
    mat query(int k,int l,int r,int sl,int sr){
        if(sl<=l&&sr>=r){
            return c[k];
        }
        int mid=(l+r)>>1;
        mat ret;
        if(sl<=mid){
            ret=query(lson(k),l,mid,sl,sr);
        }
        if(mid+1<=sr){
            if(ret.n>0){
                ret*=query(rson(k),mid+1,r,sl,sr);
            }else{
                ret=query(rson(k),mid+1,r,sl,sr);
            }
        }
        return ret;
    }
};
segtree seg;
inline int read(){
    int res=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-f;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        res=(res<<3)+(res<<1)+ch-'0';
        ch=getchar();
    }
    return f*res;
}
void write(int x){
    if(x<0){
        x=-x;
        putchar('-');
    }
    if(x>9){
        write(x/10);
    }
    putchar(x%10+'0');
}
int main(){
    int n=read();
    for(int i=1;i<=n;i++){
        int x=read();
        seg.change(1,1,n,i,x);
    }
    int q=read();
    lstres.setsize(3,1);
    lstres.A[0][0]=-inf,lstres.A[1][0]=-inf,lstres.A[2][0]=0;
    while(q--){
        int cmd=read(),x=read(),y=read();
        if(cmd==0){
            seg.change(1,1,n,x,y);
        }else{
            mat ans=seg.query(1,1,n,x,y)*lstres;
            write(ans.A[1][0]);
            putchar('\n');
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值