ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CF1498D] Bananas in a Microwave

2021-05-04 12:04:58  阅读:266  来源: 互联网

标签:香蕉 10 le curr Bananas int Microwave seen CF1498D


前言

你所能够依靠的,只有你自己。

题目

CF

洛谷

题目大意:

输入两个整数 \(n,m\) 表示操作数与目标香蕉数量。

接下来输入 \(n\) 个操作,每个操作有三个整数 \(t_i,x_i,y_i\)。令你当前的香蕉数量为 \(k\)。

  • 如果 \(t_i=1\),你可以从 \([0,y_i]\) 中选择一个数 \(a_i\) ,将 \(\lceil k+x_i\rceil\) 赋值给 \(k\),此步骤执行 \(a_i\) 次。
  • 如果 \(t_i=2\),你可以从 \([0,y_i]\) 中选择一个数 \(a_i\) ,将 \(\lceil k\cdot x_i\rceil\) 赋值给 \(k\),此步骤执行 \(a_i\) 次。

对于每一个 \(i\in[1,m]\) 输出最少操作次数使得你的香蕉数量变为 \(i\)。如果不能做到,输出 \(-1\)。

注意: \(x_i\) 可以是一个小数。

特别地,题目中的 \(x_i\) 以 \(x_i'\) 的形式输入,\(x_i'=x_i*10^5\)。

\(1\le n\le 200;2\le m\le 10^5;1\le t_i\le 2;1\le y_i \le m.\)

对于第一种操作:\(1\le x_i'\le 10^5\cdot m.\)

对于第二种操作:\(10^5< x_i'\le 10^5\cdot m.\)

讲解

看似是个 \(O(nm^2)\) 的多重背包,但实际上可以用完全背包的思路做。

思路一

假设我们什么结论都没有得出来,考虑直接 \(\tt DP\)。

我们令 \(dp_i\) 表示得到 \(i\) 根香蕉的最小操作数,\(cnt_i\) 表示当前操作下得到 \(i\) 根香蕉的最小步骤数

直接类完全背包即可。

时间复杂度 \(O(nm).\)

思路二

依然是背包,但我们先考虑证明一个结论:

如果操作相同,那么如果要得到的香蕉数量为 \(i\),最多存在一个 \(j\) 使得 \(j\) 经过一次步骤的变换后变成 \(i\)。

操作一:显然。

操作二:考虑反证。

假设存在两个数 \(j_1,j_2,j_1<j_2<i\) 使得这两个数经过一次变换后可以变成 \(i\)。令 \(x_i\) 的整数部分为 \(A_i(A_i\ge1,A_i\in N^+)\),小数部分为 \(B_i(0\le B_i<1)\)。

那么经过变换后两个数就是 \(i_1=j_1*A_i+\lceil j_1*B_i\rceil,i_2=j_2*A_i+\lceil j_2*B_i\rceil\)。

显然有 \(j_1*A_i<j_2*B_i,\lceil j_1*B_i\rceil\le\lceil j_2*B_i\rceil\)。

那么 \(i_1<i_2\),原命题不成立。

所以我们就可以直接暴力做,对于每一个之前可以得到的香蕉数,暴力更新其可以得到的香蕉数,如果更新到的香蕉数之前可以得到,那么就可以退出循环。

时间复杂度依然是 \(O(nm)\)。详见std。

坑点

  • 上取整的时候先乘再除,或者手写上取整函数,不要相信 \(\tt double\) 的精度。

  • \(\tt int\) 会爆。

代码

思路一:

LL dp[MAXM],cnt[MAXM];
 
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%lld %lld",&n,&m);
	for(int i = 1;i <= m;++ i) dp[i] = INF;
	for(int i = 1;i <= n;++ i)
	{
		double opt,x1,y;
		scanf("%lf %lf %lf",&opt,&x1,&y);
		double x = x1 / 100000.0;
		for(int j = 0;j <= m;++ j)
			if(dp[j] == INF) cnt[j] = INF;
			else cnt[j] = 0;
		for(int j = 0;j <= m;++ j)
		{
			if(dp[j] == INF) continue;
			LL W;
			if(opt == 1) W = (LL)ceil(j+x);
			else W = (LL)ceil(j*x1/100000);
			if(W <= m)
				if(cnt[j]+1 < cnt[W] && cnt[j] < y) dp[W] = i,cnt[W] = cnt[j]+1;
		}
	}
	for(int i = 1;i <= m;++ i)
		if(dp[i] == INF) printf("-1 ");
		else printf("%lld ",dp[i]);
	return 0;
}

思路二:(std)

#include <iostream>
#include <vector>

using namespace std;
using LL = long long;

const int DIV = 1e5;
inline LL ceil(LL x, LL y) {
    return (x + y - 1) / y;
}

int main() {
    int T, M; cin >> T >> M;

    vector<bool> is_seen(M + 1, false);
    is_seen[0] = true;
    vector<int> answer(M + 1, -1);
    answer[0] = 0;

    for (int timestep = 1; timestep <= T; timestep++) {
        auto new_is_seen = is_seen;

        int t, y; LL x;
        cin >> t >> x >> y;

        auto operation = [&] (long long &curr) {
            if (t == 1) {
                curr = curr + ceil(x, DIV);
            } else {
                curr = ceil(curr * x, DIV);
            }
        };

        for (int k = 0; k <= M; k++) {
            if (is_seen[k]) {
                long long curr = k;
                operation(curr);

                for (int a = 1; a <= y;) {//直接暴力更新
                    if (curr > M) break;
                    if (is_seen[curr]) break;
                    
                    new_is_seen[curr] = true;
                    answer[curr] = timestep;

                    a++;
                    operation(curr);
                }
            }
        }

        is_seen = new_is_seen;
    }

    for (int i = 1; i <= M; i++)
        cout << answer[i] << " ";

    cout << endl;
}

标签:香蕉,10,le,curr,Bananas,int,Microwave,seen,CF1498D
来源: https://www.cnblogs.com/PPLPPL/p/14729149.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有