flower 解题报告

前言

今天照常,七点四十五分开始打模拟赛,十一点四十五分时结束……

image

斯大林同志和猪在一起 猪和斯大林同志在一起 左起第三位是斯大林同志

题目描述

hzwer 有 \(n\) 种花。
一开始,hzwer 只有这些花的种子,每一天,hzwer 可以种植一种当前未开放的花,或者给一种已开放的花施肥。
\(i\) 种花有一个描述其培育难易程度的 \(m_i\) 值,当种下第 \(i\) 种新的花后,它能够从种植之日起开放 \(m_i\) 天(含当天),之后便会枯萎。比如,若一种花的 \(m_i\) 值为 \(2\),则种植之后,若不继续施肥,则它只在种植的当日和次日开放。
当给第 \(i\) 种植物施肥之后,这种花开放的时间能够额外延长 \(m_i\) 天。
hzwer 想给他的妹子办个花展(可以在进行种植/施肥之后的当天办),显然花展上这 \(n\) 种花都得开放,现在 hzwer 想知道他最早要在第几天才能给妹子办花展,如果他无论如何都办不了花展,那么就输出 Poor hzwer!

分析

首先,对于绝大部分情况都是一定有解的,只要把每一种花都反复施肥足够多次,就可以让它们支撑到花展。那么,什么情况无解呢?只当存在这样一种情况:一种花不管施多少次肥都无法支撑到另一朵开,也就是说存在两种以上花的 \(m_i=1\)
可以看到,这道题似乎用贪心不太好解决,原因是不同的花的枯萎时间难以计算,即状态很多。这让我们想到动态规划。考虑什么因素会影响某种状态下的答案:每盆花的枯萎时间都可能会影响到。注意到这道题 \(n \le 20\),所以可以用状态压缩,也就是用一个二进制数表示每盆花是否被种植。
\(f[i]\) 表示已经种植的状态为 \(i\) 的情况下,最少还需要多少天才能开花展。考虑刷表法:从已经种植的状态中去除一种,答案就是当前答案加上被去除的花所需要的天数(\(\lceil\frac{f[i]}{m_i-1}\rceil\))。
至此,这个问题已经被解决。最后注意多测要清空。

题解

#include <bits/stdc++.h>
using namespace std;
#define int long long
int dp[(1 << 18) + 10];
int n, m[20];
signed main() {
	int _;
	cin >> _;
	while (_--) {
		cin >> n;
        memset(dp, 0x3f, sizeof(dp));
		int cnt1 = 0;
		for (int i = 0; i < n; i++) {
			cin >> m[i];
			if (m[i] == 1) {
                cnt1++;
                dp[(1 << n) - (1 << i) - 1] = 1;
            }
		}
		if (cnt1 > 1) {
			cout << "Poor hzwer!\n";
			continue;
		}
		// for (int i = 0; i < n; i++) dp[1 << i] = 1;
		dp[(1 << n) - 1] = 0;
		for (int i = (1 << n) - 1; i >= 0; i--) {
			for (int j = 0; j < n; j++) {
				if (i & (1 << j)) {
					if (m[j] != 1) {
						dp[i ^ (1 << j)] = min(dp[i ^ (1 << j)], dp[i] + max(1ll, (dp[i] - 1) / (m[j] - 1) + 1));
					}
				}
			}
		}
		cout << dp[0] << '\n';
	}
	return 0;
}

结语

……挂了很多分,和正解没挨上一点边,算是非常坏了!

posted @ 2025-06-04 11:35  cwkapn  阅读(22)  评论(0)    收藏  举报