题意大致是Bob新年拿红包,每个红包可以在s-t时间内取,但是取了之后得在d+1时间开始才能继续取红包。
同时他女儿能在m个时间点阻止他取红包,求女儿阻止后Bob取得的w总和最小值。
Bob取红包的策略是固定的,有红包就一定取,有多个就取w最大的,仍然有多个就取d最大的。
这个题意读了半天,不得不感叹Bob他孩子真是亲生的,都是傻子ww。
这个题首先第一感觉就是个典型的dp,但是想了想觉得女儿的阻止操作会影响后续当时状态的红包状态,纠结了半天。
但是其实我们可以发现,首先Bob的操作本来应该是固定的,每个时间红包状态显然也是固定的。
Bob的女儿的影响其实是不会改变每个时间取的红包,取了红包后转移到d+1时刻,而被阻止了取红包是转移到now+1时刻。
所以说,我们只要在每个时刻用优先队列得到当时根据Bob策略要取的红包,直接进行转移即可。
#include<bits/stdc++.h>
using namespace std;
int i,i0,n,m,k;
long long dp[100005][205];
struct node
{
int s,t,d,w;
}a[100005];
bool cmp(node a,node b){return a.s<b.s;}
struct cmp0{
bool operator()(node a,node b)
{
if(a.w==b.w)return a.d<b.d;
return a.w<b.w;}
};
priority_queue<node,vector<node>,cmp0>q;
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(i=1;i<=k;i++)scanf("%d %d %d %d",&a[i].s,&a[i].t,&a[i].d,&a[i].w);
sort(a+1,a+1+k,cmp);
for(i=2;i<=n+1;i++)for(i0=0;i0<=m;i0++)dp[i][i0]=(long long)INT_MAX*INT_MAX/2;
for(i=1,i0=1;i<=n;i++)
{
while(i0<=k&&a[i0].s==i)q.push(a[i0++]);
while(!q.empty()&&q.top().t<i)q.pop();
if(q.empty())
{
for(int i1=0;i1<=m;i1++)dp[i+1][i1]=min(dp[i+1][i1],dp[i][i1]);
}
else
{
for(int i1=0;i1<=m;i1++)dp[q.top().d+1][i1]=min(dp[q.top().d+1][i1],dp[i][i1]+q.top().w);
for(int i1=0;i1<m;i1++)dp[i+1][i1+1]=min(dp[i+1][i1+1],dp[i][i1]);
}
}
long long ans=(long long)INT_MAX*INT_MAX/2;
for(i=0;i<=m;i++)ans=min(ans,dp[n+1][i]);
printf("%lld\n",ans);
return 0;
}