P2034 選擇數字

纯粹的發表於2024-03-09

原題連結

題解

不能連續選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;
}

相關文章