F. Feed Cats

纯粹的發表於2024-07-07

原題連結

題解

每個點要麼喂,要麼不喂,我們令 \(dp[i]\) 為前 \(i\) 個步驟最多能餵養多少貓,易得 \(dp[i]\) 是單調不減的
我們再維護每個點被包含的區間裡的最左端 \(l\)
這樣一來 \(dp[i]=max(dp[i-1],dp[l-1]+sum)\)

可是如何維護每個點被包含區間的最左端呢?
我們先記錄下每個右端點的最小左端點,然後逆序遍歷,即對於 \(i\) 求以 \([i,n]\) 內為右端點的最小左端點

code

#include<bits/stdc++.h>
using namespace std;

int farl[2000005],pre[1000006]={0},dp[1000006];
int main()
{
    int t;
    cin>>t;

    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            farl[i]=n+1;
            pre[i]=0;
        }

        for(int i=1;i<=m;i++)
        {
            int x,y;
            cin>>x>>y;
            pre[x]++;
            pre[y+1]--;

            farl[y]=min(farl[y],x);
        }

        for(int i=n-1;i>=1;i--) farl[i]=min(farl[i],farl[i+1]);

        int sum=0,ans=0;
        for(int i=1;i<=n;i++)
        {
            sum+=pre[i];

            dp[i]=dp[i-1];
            if(farl[i]<=i) dp[i]=max(dp[i],dp[farl[i]-1]+sum);
            ans=max(ans,dp[i]);
        }
        cout<<ans<<'\n';
    }
    return 0;
}

相關文章