首页 > 其他分享 >饭票 题解

饭票 题解

时间:2023-08-02 16:13:50浏览次数:36  
标签:int 题解 凑出 饭票 数组 面值 dp

1.题意简述

某天小 \(x\) 去食堂吃饭,手里有 \(n\) 种饭票,面值分别为 \(A_1~A_n\) ,数量分别为 \(C_1~C_n\) 请你计算小 \(x\) 的饭票能组成多少在 \([1,m]\) 区间内的面值。

2.样例解释

3 10
1 2 4 2 1 1
8

样例中,我们有两张一元,一张两元和一张四元,可以凑出 \(1\) 到 \(8\) 元中所有面值,故答案为 \(8\)。

3.思路

1.90分思路

我们先定义一个长度为 \(m\) 的布尔数组,用于存储每种面值是否被凑到过,在最开始将 \(0\) 元打上逻辑真标记,表示 \(0\) 元可以被凑出。

然后对于第 \(i (1 \leq i \leq n)\) 种面值 \(a_i\) 何其对应张数 \(c_i\), 只需从之前打上标记的所有面值出发重复 \(c_i\) 次将比当前点大 \(a_i\) 的点打上逻辑真,最后遍历整个数组输出逻辑真的个数即可。

代码如下:

dp[0] = 1;
v.push_back (0);

For (i, 1, n) {
	p = 0, len = v.size ();
	for (int j = 0; j < len; j ++) {
		int now = v[j];
		for (int k = 1; k <= a[i].c; k ++) {
			if (now + a[i].a * k > m) break;
			if (dp[now + a[i].a * k] == 0) {
				ans ++;
				dp[now + a[i].a * k] = 1;
				v.push_back (now + a[i].a * k);
			}
		}
	}
}
cout << ans << endl;

2.100分思路

还是可以定义逻辑数组存储面值是否能凑到,还是将面值 \(0\) 标记为1,不同的是这次我们在遍历 \(n\) 的点时再直接枚举面值,也就是说从 \(1\) 枚举到 \(m\),在之前已经能凑出来的面值的基础上加上当前饭票面值 \(a_i\)。

如果新凑出的面值之前没有凑出过且在 \(1\) 到 \(m\) 的范围内,就将 \(ans\) 加上1。

我们新开一个 \(dp[i][j]\) 数组,表示若要凑出 \(j\) 元面值需要多少张 \(a_i\) 元饭票(变相说明 \(dp_{(i, j=(1,2,3...m)} \leq c_i\) )所以当每次能更新时,就用如下状态转移方程:$$dp_{(i,j+a_i)} = dp_{(i,j)} + 1$$

此外还要注意一点:即使这个点已经被凑出来,但代进去不满足上述方程,也需要更新一下。。。

3.代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
//define int long long

using namespace std;

#define N 100010
#define For(i,j,k) for(int i=j;i<=k;i++)
#define IOS ios::sync_with_stdio(),cin.tie(),cout.tie()

int n, m, ans = 0, dp[110][100010];
bool ok[N];
struct no {
	int a, c;
}a[N];

int main () {
    IOS;
	cin >> n >> m;
	For (i, 1, n) cin >> a[i].a;
	For (i, 1, n) cin >> a[i].c;
	ok[0] = true; //将面值 0 标记为true

	For (i, 1, n) {
		For (j, 0, m) { //从面值0枚举到面值m
			if (ok[j] && dp[i][j] < a[i].c) { 
			//如果面值j已被凑出来过,且接下来凑出的面值确保使用不超过 c[i] 张
				if (!ok[j + a[i].a] && j + a[i].a <= m) {
				//如果接下来凑出来的面值之前没有凑出来过,并且在 1~m 的范围内
					ans ++; //记录结果
					ok[j + a[i].a] = true; //标记面值为true
					dp[i][j + a[i].a] = dp[i][j] + 1; 
					//面值j使用的饭票数量是它派生出的面值的使用饭票数量+1
				} else if (dp[i][j + a[i].a] > dp[i][j] + 1){
				//如果已经被凑出来过,但是不满足方程
					dp[i][j + a[i].a] = dp[i][j] + 1;
					//维护一下数组,令其符合方程
				}
			}
		}
	}

	cout << ans << endl; //输出
	return 0;
}

4.一个可以有的小优化

事实上,在循环时 \(dp\) 数组的第一维并没有派上用场,所以我们可以将 \(dp\) 数组开成一维的,并在每次清空一下即可,这样一来可以大大减小空间复杂度,但对应的,时间复杂度也会更高。

下面是开了二维与不开二维的区别 (\(c++ 17\)):

开了二维:image
不开二维:image

标签:int,题解,凑出,饭票,数组,面值,dp
From: https://www.cnblogs.com/linbaicheng/p/17600925.html

相关文章

  • 【题解】Luogu[P2296] [NOIP2014 提高组] 寻找道路
    Link很简单的一道图论题。要在一个有向图上找一条\(s\)到\(t\)的最短路,要求这条路径上的所有点都满足:该点的所有出边所连点都能到达终点\(t\)。看上去很乱,我们简单分解一下,先在所有点中找到与终点有路径的点集\(A\)进行标记,再再所有点中找到其所有出边所连点都被打上标......
  • 国标GB28181视频平台LntonGBS国标平台调用快照接口,未能正常返回快照图片的问题解决方
    LntonGBS国标视频云服务支持设备/平台通过国标GB28181协议注册接入,可实现视频的实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。LntonGBS平台便捷、丰富、灵活、可拓展的视频能力,已经使其成为当前安防市场的主流需求视频平台,并且已经在大量的项目中落地......
  • 【题解】HDOJ 7329 [2023杭电多校] Touhou Red Red Blue
    题目传送门:HDOJ7329[2023杭电多校]TouhouRedRedBlue题意有两个口袋(口袋容量为1,初始均为空),有若干个UFO按顺序来到你的面前,每个UFO有一个颜色(GRB),你可以选择扔掉它或者把它装进口袋中,如果口袋1空着必须装进口袋1;如果口袋都满了,算上面前的UFO共有三个,有如下三种情况:如......
  • NOI2023 题解
    打的太shaber了,于是补补题。D1T1扫描线。首先我们可以容斥一下,答案为被一种操作覆盖到的减去被两种操作覆盖到的加上被三种操作覆盖到的。首先考虑只被一种操作覆盖到的,这很简单,直接上个区间颜色段推平就好了,顺便去了个重。接下来是有被斜线覆盖到的,这样的点数为\(O(nk)\)......
  • 因MySQL数据库无法启动导致LiteCVR视频平台也无法启动的问题解决教程
    近期呢,我们的数据人员发现有时候MySQL数据库无法启动会导致LiteCVR视频平台也无法启动,所以接下来我们将为大家讲解遇见这种问题时的解决教程。但是在这之前值得一提的一件事那就是我们的LiteCVR平台默认的数据库是SQLite,不过用户可以根据自己的使用需求选择将数据库切换为MySQL。具......
  • [MySQL] 调用定时器时event_scheduler是Off问题解决
    永久解决方法:修改MySQL配置文件,设置event_scheduler=ONvi/etc/my.cnf在[mysqld]下添加一行重启mysql服务event_scheduler=ON临时方法执行mysql语句1、查看事件调度器状态showVARIABLESlike'event_scheduler'......
  • 统信UOS专业版 apt update失败问题解决方法
    UOSaptupdate时提示‘仓库“https://pro-store-packages.uniontech.com/appstoreeagle-proInRelease”的签名不再生效’只需要更改/etc/apt/sources.list.d/appstore.list文件内容,改为debhttps://com-store-packages.uniontech.com/appstoredeepinappstore同时,建......
  • ABC311E 题解
    看到官方题解是\(O(n^2)\)的dp。提供一个\(O(n^2\log_2n)\)的做法,考场思路,大概比较简单。Description给一个\(H\)行\(W\)列的网格,其中一些点被涂成黑色,求整个正方形内都未被涂黑的正方形的个数。Solution考场上首先想到的简单暴力做法,即枚举正方形左上角端点,然......
  • CF1594A 题解
    题意\(t\)组数据(\(1\let\le1000\)),每组数据给一个整数\(n\)(\(1\len\le10^{18}\)),找出两个整数\(l\)和\(r\)($-10^{18}\lel<r\le10^{18}$)使$l+(l+1)+\ldots+(r-1)+r=n$。思路看到这个题目,首先会想到\(l=n\)且\(r=n\),但是发现题目要求\(......
  • CF1702E 题解
    题意\(t\)组数据($1\let\le10^{4}$),每组数据给一个偶数\(n\)(\(2\len\le2\cdot10^{5}\)),有\(n\)个多米诺骨牌,每块多米诺骨牌包含两个整数\(a_{i}\)和\(b_{i}\)(\(1\lea_{i},b_{i}\len\)),要求把这\(n\)块多米诺骨牌分入两个集合使得每个集合中的数互不相同,每个......