首页 > 其他分享 >P1941 NOIP2014 提高组 飞扬的小鸟 题解

P1941 NOIP2014 提高组 飞扬的小鸟 题解

时间:2024-10-16 16:37:21浏览次数:1  
标签:NOIP2014 int 题解 点击 背包 maxn P1941

P1941 NOIP2014 提高组 飞扬的小鸟

分析

背包经典演变问题玩得挺花

设 \(f[i][j]\) 表示 到达 \((i, j)\) 的时候的最小点击次数。题目中对于每一个 \(i\) 有两种处理:点击与不点击(重点:点击可以叠加)。所以,对于点击,我们可以像完全背包一样转移,而不点击就按照 01 背包转移。

对于管道,我们把管道的 \(f[i][j]\) 设为 \(\inf\) 表示无法到达。

点击之后高度可能超过 \(m\),但是题目说了最高到 \(m\),所以超过 \(m\) 的一律当在 \(m\) 高度处理。

代码里有详细说明。

代码 | 解析

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

const int maxn = 10005;
const int maxm = 2005;
int n, m, k;
int up[maxn], down[maxn];
int low[maxn], high[maxn];
// f[i][j]:到达 (i, j) 时的最小点击次数。
int f[maxn][maxm]; // 可选择点击与不点击,点击可以叠加;点击按照完全背包转移,不点击按照 01 背包转移。
bool isPipe[maxn];

int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d", &up[i], &down[i]);
	}
	for (int i = 1; i <= k; i++) {
		int p, l, h;
		scanf("%d%d%d", &p, &l, &h);
		isPipe[p] = true, low[p] = l, high[p] = h;
	}
	memset(f, 0x3f, sizeof(f));
	for (int i = 1; i <= m; i++) f[0][i] = 0;
	for (int i = 1; i <= n; i++) {
		// 向上(点击)按照完全背包转移。
		for (int j = up[i] + 1; j <= m + up[i]; j++) {
			f[i][j] = min(f[i - 1][j - up[i]] + 1, f[i][j - up[i]] + 1);
		}
		// 点击之后向上飞可能超过 m,但是题目说了最高飞到 m,可以一直贴着最顶上飞。
		for (int j = m + 1; j <= m + up[i]; j++) {
			f[i][m] = min(f[i][j], f[i][m]); // 所以处理一下。
		}
		// 向下(不点击)按照 01 背包转移
		for (int j = 1; j <= m - down[i]; j++) {
			// 为什么 01 背包不从大到小枚举?
			// 因为用 f[i-1][j+down[i]] 来转移,所以从 1 到 m-down[i] 才是 01 背包。
			f[i][j] = min(f[i][j], f[i - 1][j + down[i]]);
		}
		// 刚才把 i 列当作没有管道(障碍)了,若 i 列是管道,则需要消除影响。
		if (isPipe[i]) {
			for (int j = 1; j <= low[i]; j++) {
				f[i][j] = 0x3f3f3f3f;
			}
			for (int j = high[i]; j <= m; j++) {
				f[i][j] = 0x3f3f3f3f;
			}
		}
	}
	int ans = 0x3f3f3f3f;
	for (int i = 1; i <= m; i++) {
		ans = min(ans, f[n][i]);
	}
	if (ans < 0x3f3f3f3f) {
		printf("1\n%d", ans);
	} else {
		// 无法完成游戏。
		ans = 0;
		bool flag = true;
		int endpos = 0;
		for (int i = n; i >= 1; i--) {
			for (int j = 1; j <= m; j++) {
				if (f[i][j] < 0x3f3f3f3f) {
					flag = false;
					endpos = i; // 最后可以到达的地方。
					break;
				}
			}
			if (!flag) break;
		}
		// 统计所有经过的管道。
		for (int i = 1; i <= endpos; i++) {
			if (isPipe[i]) ans++;
		}
		printf("0\n%d", ans);
	}
	return 0;
}

标签:NOIP2014,int,题解,点击,背包,maxn,P1941
From: https://www.cnblogs.com/jxyanglinus/p/18470232

相关文章

  • [NOI2020] 美食家 题解
    属于是将矩阵快速幂的绝大部分技巧用到了极致的一道题。暴力部分首先我们先考虑一个普通DP。定义\(dp_{t,i}\)表示在时间为\(t\)时到达点\(i\)可以得到的愉悦值之和的最大值。显然有\((i,j)\inE\todp_{t+w,j}=\max(dp_{t,i}+c_j)\)。特判一下当前节点有美食节的情......
  • 洛谷 P5175 数列 题解
    纯纯数学题。看到\(n\le10^{18}\)不难想到矩乘,但是\(\log_210^{18}\approx60\),再加上\(T=30000\)的多测,运算量已经来到了\(1.8\times10^6\),所以我们最多有一个\(\sqrt[3]{\frac{1.5\times10^8}{6\times10^6}}\approx4\)的矩阵。\[\becausea_i=xa_{i-1}+ya_{......
  • Project Euler 588 题解
    这玩意好像甚至有递推式……不太懂(为什么是图片?cnblogs第一个公式没渲染成功)时间复杂度是\(O(4^{\degF}\logK)\)的。#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintmaxn=100;intf[17][maxn],cur[10],al[4];intcalc(intK){ //cer......
  • 题解:[SNCPC2019] Pick Up
    ProblemLink[SNCPC2019]PickUp题意给出甲的坐标和速度,乙的坐标和速度,商场的坐标,可以让乙去接甲,求甲前往商场的最短用时。Solution分类讨论。思考乙是否要去接甲。这个很简单,令\(ans1\)为甲自己出发耗时,\(ans2\)为乙接甲耗时,两者取最小值即可。\(ans1\)很好算,那么\(......
  • P3794 签到题IV 题解
    题目传送门前置知识最大公约数解法\(\gcd\)和\(\operatorname{or}\)在固定左端点的情况下至多会变化\(O(\logV)\)次。以\(\gcd\)为例,考虑求出所有的四元组\((l,r,x,val)\)表示\(\foralli\in[l,r],\gcd\limits_{j=i}^{x}\{a_{j}\}=val\)。本题中因为\(x\)......
  • CF1458D Flip and Reverse 题解
    思路由于它要求\(\text{01}\)数量相等,我们可以考虑站在前缀和的角度看待这个问题。我们将\(0\)看作负一,\(1\)看作一。可以把它化成一个折线图(方便观察)。观察一下它的操作实际上在干什么。容易发现,在折线图上,我们把操作的\([l,r]\)的整段折线reverse了一遍。同样的,......
  • [题解]CF1136E Nastya Hasn't Written a Legend
    思路首先考虑操作1一个点\(i\)能被操作到的条件。注意到此时\(x\simi-1\)这些位置都是被更新过的,再仔细观察此时\(\forallj\in[x,i),a_j=a_x+\sum_{p=x}^{j-1}k_p\)。那么对于\(a_i\)如果会被修改将会变为\(a_x+\sum_{p=x}^{i-1}k_p\),那么\(a_i......
  • [ABC213G] Connectivity 2 题解
    T3[ABC213G]Connectivity2题意:给定一张无向图\(G\),将其删去\(0\) 条及以上的边构成一张新图,求对于所有点\(k\in(1,n]\),使\(k\) 与\(1\) 连通的新图的个数。比较套路的一道状压DP。尽管刚开始思考毫无头绪。Step1.令\(f_S\)表示点集为\(S\)的连通子图的个数,\(......
  • [TJOI2018] 游园会 题解
    T7[TJOI2018]游园会只能说是道有意思的好题。一般来说遇到这种题我们想到的都会是设\(f_{i,\dots}\)表示长度为\(i\),然后后面跟一堆状态的情况。此题需要我们满足两个条件:LCS的长度;不能出现\(\texttt{NOI}\)的子串。第二个限制我们可以通过状态设计来解决,但第一个......
  • [JSOI2018] 潜入行动 题解
    T6[JSOI2018]潜入行动很套路、很裸的一道树形DP。看了状态就会推方程的那种。设\(f_{u,i,0/1,0/1}\)表示以\(u\)为根的子树中有\(i\)个监听器、\(u\)有没有监听器、\(u\)有没有被监听的方案数。显然要枚举子节点\(v\)、\(u\)的监听器数量\(i\)、\(v\)的监听器数......