解题思路:先把月份和天数换算成一年第几天,然后从小到大排序。然后进行动态规划,dp[i][j]表示选到第i个为止时金额j是否能取到,last代表第i个之前的最近的距离i时间差大于等于k的序号。如果没有last就等于0。状态转移方程:dp[i][j] = dp[i - 1][j] | (j >= a[i].v ? dp[last][j - a[i].v] : 0)
注意事项:
每个序号转移之前可以先把的dp[i-1]复制过来。因为前一个的天数要小于等于这一个,所以到前一个的天数位置能取到的到这一个的天数肯定也能取到。
参考代码:

#include <bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define endl "\n"
#define pb push_back
#define getl(s) getline(cin,s)
#define max(a,b) a > b ? a : b
#define min(a,b) a < b ? a : b
#define abs(a)   a > 0 ? a : -a
#define lowbit(a) a & -a
using namespace std;
const int N = 1e3 + 5;
const int M = 5e3 + 5;
struct node 
{
	int day,v;
}a[N];
int n,m,k,dp[N][M];//dp[i][j]代表选择到第i个时金额j是否能取到 
int mon[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int getday(int m,int d)
{
	int res = 0;
	for(int i = 0;i < m;i++)
		res += mon[i];
	return res + d;
} 
bool cmp(node x,node y)
{
	return x.day < y.day;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>k;
	memset(dp,0,sizeof(dp));
	dp[0][0] = 1;
	for(int i = 1;i <= n;i++)
	{
		dp[i][0] = 1;
		int m,d;cin>>m>>d>>a[i].v;
		a[i].day = getday(m,d);
	}
	//按照时间先后顺序排列 
	sort(a + 1,a + n + 1,cmp);
	for(int i = 1;i <= n;i++)
	{
		int last = i - 1;
		//找到最近的距离i超过k天的序号 
		while(a[i].day - k < a[last].day && last > 0)last--;
		for(int j = m;j >= 0;j--)
		{
			dp[i][j] = dp[i - 1][j];
			if(j >= a[i].v)dp[i][j] |= dp[last][j - a[i].v];
		}	
	}
	for(int i = m;i >= 0;i--)
		if(dp[n][i])
		{
			cout<<i;
			break;		
		}
	return 0;
}


点赞(0)
 

0.0分

15 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 2 条评论

AUDeserve 8月前 回复TA
太强了
nakija 10月前 回复TA
搞不懂