第十三届蓝桥杯C++B组国赛F题——费用报销 (AC)

1.费用报销

1.问题描述

小明在出差结束后返回了公司所在的城市, 在填写差旅报销申请时, 粗心 的小明发现自己弄丢了出差过程中的票据。

为了弥补小明的损失, 公司同意小明用别的票据进行报销, 但是公司财务 要求小明提交的票据中任意两张的日期差不小于 K K K 天, 且总金额不得超过实际 差旅费用 M M M

比如财务要求 K = 7 K=7 K=7 时, 若小明提交了一张 1 月 8 日的票据, 小明就不能 提交 1 月 2 日至 1 月 14 日之间的其他票据, 1 月 1 日及之前和 1 月 15 日及之 后的票据则可以提交。

公司的同事们一起给小明凑了 N N N 张票据, 小明现在想要请你帮他整理一 下, 从中选取出符合财务要求的票据, 并使总金额尽可能接近 M M M

需要注意, 由于这些票据都是同一年的, 因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。

2.输入格式

1 1 1 行: 3 个整数, N , M , K N, M, K N,M,K
2 … N + 1 2 \ldots N+1 2N+1 行: 每行 3 个整数 m i , d i , v i m_{i}, d_{i}, v_{i} mi,di,vi, 第 i + 1 i+1 i+1 行表示第 i i i 张票据时间 的月份 m i m_{i} mi 和日期 d i , v i d_{i}, v_{i} di,vi表示该票据的面值

3.输出格式

第 1 行: 1 个整数, 表示小明能够凑出的最大报销金额

4.样例输入

4 16 3
1 1 1
1 3 2
1 4 4
1 6 8

5.样例输出

10

6.数据范围

1 ≤ N ≤ 1000 , 1 ≤ M ≤ 5000 , 1 ≤ K ≤ 50 , 1 ≤ m i ≤ 12 , 1 ≤ d i ≤ 31 , 1 ≤ v i ≤ 40012 , 1 ≤ d i ≤ 31 , 1 ≤ v i ≤ 400 1≤N≤1000,1≤M≤5000,1≤K≤50,1≤m i≤ 12,1 \leq d_{i} \leq 31,1 \leq v_{i} \leq 40012,1≤di ≤31,1≤vi≤400 1N1000,1M5000,1K50,1mi12,1di31,1vi40012,1di31,1vi400

7.原题链接

费用报销

2.解题思路

这是一道比较明显的01背包问题,涉及物品的选择。这些票据都有月份和天数,为了方便比较,我们将其全部转换为天数,使用pair存下天数和票额,然后根据天数来进行排序。

定义bool数组f[i][j],含义为只考虑前i个物品,能否组成价值为j的情况。当我们枚举到票据i时,假设它的天数为 x x x,如果我们选了票据i,那么票据日期 [ x − k , x ] [x-k,x] [xk,x]都是不可取的。所以我们需要使用双指针维护每一个票据i上一个和他日期相差大于k天的票据l

接下来进行状态转移的分析,当 j < t [ i ] . s e c o n d j<t[i].second j<t[i].second(表示排序后第 i i i 个票据的价值),说明我们的票据价值太大,无法选择,转化为背包思想就是我们的物品太重背包放不下。此时状态转移就为 f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i1][j]。当 j > = t [ i ] . s e c o n d j>=t[i].second j>=t[i].second时,说明当前票据我们是可选的,我们有两种抉择——选还是不选?如果我们不选择它,那么转移方程同上。如果我们选择它,那么状态转移时就不一定是从上一个物品转移过来,题意要求两件任意的两张票据需要至少间隔k天,我们应该从上一张比当前票据至少少k天的票据l转移过来,那么状态转移方程为: f [ i − 1 ] [ j ] ∣ f [ l ] [ j − t [ i ] . s e c o n d ] f[i-1][j] | f[l][j-t[i].second] f[i1][j]f[l][jt[i].second]

将转移方程结合起来,上面是可选状态,下面是不可选状态:
f [ i ] [ j ] = { f [ i − 1 ] [ j ] if j<t[i].second f [ i − 1 ] [ j ] ∣ f [ l ] [ j − t [ i ] . s e c o n d ] if j>=t[i].secode f[i][j]= \begin{cases} f[i-1][j] &\text{if j<t[i].second}\\ f[i-1][j] | f[l][j-t[i].second] &\text{if j>=t[i].secode}\\ \end{cases} f[i][j]={f[i1][j]f[i1][j]f[l][jt[i].second]if j<t[i].secondif j>=t[i].secode

当然因为是01背包问题,我们也可以使用滚动数组优化,这里为了方便大家理解就没有进行优化。最后从最大体积 M M M 倒着遍历体积 V V V,那么第一个 d p [ n ] [ V ] = t r u e dp[n][V] = true dp[n][V]=true 对应的 V V V 即为答案。

时间复杂度: O ( n m ) O(nm) O(nm)

3. AC_code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;;
const int N=1010;

int n,m,k;
int w[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
PII t[N];
//只考虑前i个物品能否组成体积为j的情况
bool f[N][5*N];
int main() 
{
	for(int i=1;i<=12;++i) w[i]+=w[i-1];
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;++i){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		t[i]={w[a-1]+b,c};
	}
	//按日期排序
	sort(t+1,t+n+1);
	f[0][0]=true;
	//双指针
	int l=0;
	for(int i=1;i<=n;++i){
		//找到上一个可选的票据
		while(t[i].first-t[l+1].first>=k) l++;
		for(int j=0;j<=m;++j){
			f[i][j]=f[i-1][j];
			if(j>=t[i].second) f[i][j]|=f[l][j-t[i].second];
		}
	}
	for(int v=m;v>=0;--v){
		if(f[n][v]){
			printf("%d\n",v);
			return 0;
		}
	}
}
  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
费用报销规定 第一条 现金报销需填制报销凭证,按凭证内容要求在"摘要"处填写报销内容及金额,由部门经理、审核人员、总经理审核签字后交财务核报。(附流程)。 第二条 申购物品须事先填制物品申购单,经部门经理、办公室签字后交财务部,物品单价在300元以上(含300元)须总经理审核签字,未经审批,擅自购买者不得报销。财务人员审核时应对照已收到的申购单。购买物品原则上由办公室办理,专业用品自行购买后至办公室办理登记后财务核报。(附流程) 第三条 员工因工作需要不能回公司就餐的,可凭发票每人每餐报销10元。外出联系工作,应乘坐公交车辆,按实报销,若有特殊情况,经部门经理事先同意方可乘坐出租车辆,报销时须在发票上写明出发地、目的地。 第四条 业务招待费:因工作需要招待客户或赠送礼品,费用在1000元以上者应事先填制特批单,报总经理审核签字后交财务部,财务人员审核时应对照已收到的特批单。员工因工作需要所支付的业务招待费在报销时须向部门经理、审核人员主动说明,并由经办人及部门经理在该张发票背后签字。(附流程) 第五条 市外差旅费:员工因公赴外省、市出差,路程超过六小时及需要过夜的可购买硬卧火车票,轮船票不超过三等舱位;遇有急事需乘飞机的,必须事先填制特批单,经总经理签字后交财务部。财务人员审核报销时须对照已收到的特批单。住宿费每日标准为150元,伙食补贴每日80元,上述两项费用可累计使用。(附流程)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执 梗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值