• P3800 Power收集


    传送门

    DP
    每次向下一格,显然是DP
    方程也十分显然:
    设$f[i][j]$为到第$i$行第$j$列时能得到的最大价值
    显然$f[i][j]=max(f[i-1][k]+v[i][j]),( max(0,j-t)<=k<=min(m,j+t) )$
    然后40分,其他超时..
    考虑优化
    方程稍微变一下:$f[i][j]=max(f[i-1][k])+v[i][j],$
    同样$max(0,j-t)<=k<=min(m,j+t)$;
    发现只要能快速处理出$f[i-1][k]$的最大值就能快速更新$f[i][j]$
    因为区间大小不会改变(不考虑达到边界),改变的只有区间的开端,所以可以考虑通过单调队列预处理..
    然后就结束了,稍微注意边界问题就好了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int n,m,k,t;
    int map[4005][4005],f[4005][4005];
    int q[4005],ans[10005];
    int main()
    {
        int a,b,c;
        cin>>n>>m>>k>>t;
        int s=t*2+1;
        while(k--)
        {
            scanf("%d%d%d",&a,&b,&c);
            map[a][b]=c;
        }
        //cout<<endl;
        for(int i=1;i<=n;i++)
        {
            int head=1,last=0;
            //单调队列预处理
            for(int j=1;j<=m+t;j++)//注意j到m+t
            {
                while(head<=last&&f[i-1][j]>=f[i-1][q[last]])
                    last--;
                while(head<=last&&j-q[head]>=s)
                    head++;
                q[++last]=j;
                ans[j]=f[i-1][q[head]];
                //cout<<ans[j]<<" ";
            }
            for(int j=1;j<=m;j++)
                f[i][j]=ans[j+t]+map[i][j];
            //cout<<endl;
        }
        int Ans=0;
        for(int i=1;i<=m;i++)
            Ans=max(Ans,f[n][i]);
        cout<<Ans;
        return 0;
    }
  • 相关阅读:
    14. HTML 列表(无序, 有序, 定义)
    13. HTML table
    12. HTML图像
    11. HTML链接
    10. HTML CSS
    learning java AWT Pannel
    learning AWT Jrame
    learning java 正则表达式
    learning java java.time相关类
    learning java Calendar类
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9506699.html
Copyright © 2020-2023  润新知