P2034 选择数字

原题链接

题解

不能连续选k个元素 \(\to\) 任意每k个元素就有一个不选 \(\to\) 每k个点就有一个断点
\(\to\) 每个点都有可能是断点 \(\to\) dp求解

\(sol.1\)
\(f[i]\) 为第i个点为断点且为结尾的最大值
\(f[i]=max(f[j]+sum[j+1,i-1])\)

\(sol.2\)
至少每隔k个点就取一个点,取点和的最小值

\(code1\),优先队列,\(O(n·logn)\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node
{
    ll v,x;
    bool operator <(const node &b)const {return b.v<v;}
};
ll dp[1000005]={0};
ll a[1000005];
int main()
{
    ll n,k,sum=0;
    cin>>n>>k;
    for(ll i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }

    priority_queue<node> q;
    ll ans=2e18;
    for(ll i=1;i<=n;i++)
    {
        q.push({dp[i-1],i-1});
        while(q.size()&&i-q.top().x>k+1) q.pop();
        dp[i]=a[i];
        if(q.size()) dp[i]+=q.top().v;
        if(i+k>=n)ans=min(ans,dp[i]);
        //cout<<dp[i]<<endl;
    }

    cout<<sum-ans;
    return 0;
}

\(code2\),单调队列,\(O(n)\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll sum[1000005]={0},f[100005]={0};
ll a[1000005];
int main()
{
    ll n,k;
    cin>>n>>k;
    for(ll i=1;i<=n;i++)
    {
        cin>>a[i];
        sum[i]=sum[i-1]+a[i];
    }

    deque<ll> q;
    q.push_back(0);
    for(int i=1;i<=n;i++)
    {
        if(q.size()&&i-q.front()>k+1)q.pop_front();

        if(q.size())  f[i]=f[q.front()]+sum[i-1]-sum[q.front()];
        while(q.size()&&f[q.back()]-sum[q.back()]<=f[i]-sum[i]) q.pop_back();
        q.push_back(i);
        //cout<<f[i]<<endl;
    }

    if(q.size()&&n-q.front()>k) q.pop_front();
    cout<<f[q.front()]+sum[n]-sum[q.front()];
    return 0;
}
posted @ 2024-03-09 16:40  纯粹的  阅读(45)  评论(0)    收藏  举报