算法复习 - AcWing动态规划

1027. 方格取数

从左上角走到右下角,能走两次,问你最大收益,两条路如果走到同一个点就只有一份收益

特殊情况就是两条路重复的时候,重复的必要条件是两条路走的步数相等,为了方便维护这个值,DP维护的状态中保存当前走的总步数和第一二条路向右走的步数,这样向下走的步数可以直接计算出,状态转移就很明显了就


/*
dp[i1][i2][k]: 第一个点走到(i1,k-i1),第二个点走到(i2,k-i2)的最大值
dp[i1][i2][k] 可由 dp[i1][i2][k-1],dp[i1-1][i2][k-1],dp[]
*/

int mp[111][111];
int dp[22][22][44];
void solve()
{
    int n;cin>>n;
    int x,y,z;
    while(cin>>x>>y>>z&&(x|y|z)) mp[x][y]=z;
    int ans=0;
    for(int k=2;k<=n+n;++k)
        for(int i1=1;i1<min(n+1,k);++i1)
            for(int i2=1;i2<min(n+1,k);++i2)
            {
                int tmp=(i1==i2?mp[i1][k-i1]:mp[i1][k-i1]+mp[i2][k-i2]);
                dp[i1][i2][k]=tmp+max(max(dp[i1-1][i2][k-1],dp[i1][i2-1][k-1]),max(dp[i1][i2][k-1],dp[i1-1][i2-1][k-1]));
                if(k==n+n) ans=max(ans,dp[i1][i2][k]);
            }
    cout<<ans<<endl;
}
135. 最大子序和

找长不超过m的最大子段和
区间和,考虑前缀和,对于对于每一个右端点,找一个最小的左端点,且长度在m内,使用单调队列
队列中越靠近队头的元素,越早入队

int a[MX];
void solve()
{
    int n,m;cin>>n>>m;
    deque<pair<int,int>>q;//维护一个单调递增队列
    int ans=-0x3f3f3f;
    rpp(i,n) cin>>a[i],ans=max(ans,a[i]),a[i]+=a[i-1];
    q.push_back(make_pair(0,0));
    rpp(i,n) 
    {
        while(q.size()&&i-q.front().first>m) q.pop_front();
        if(q.size()) ans=max(ans,a[i]-q.front().second);
        while(q.size()&&q.back().second>=a[i]) q.pop_back();
        q.push_back(make_pair(i,a[i]));
    }
    cout<<ans<<endl;
}
896. 最长上升子序列 II

O(nlhn)的LIS,维护每个长度的上升子序列末尾的最小值
整个代码都很精妙)%%%%

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(void) {
    int n; cin >> n;
    vector<int>arr(n);
    for (int i = 0; i < n; ++i)cin >> arr[i];

    vector<int>stk;//模拟堆栈
    stk.push_back(arr[0]);

    for (int i = 1; i < n; ++i) {
        if (arr[i] > stk.back())//如果该元素大于栈顶元素,将该元素入栈
            stk.push_back(arr[i]);
        else//替换掉第一个大于或者等于这个数字的那个数
            *lower_bound(stk.begin(), stk.end(), arr[i]) = arr[i];
    }
    cout << stk.size() << endl;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值