• [CF1498D] Bananas in a Microwave


    前言

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

    题目

    CF

    洛谷

    题目大意:

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

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

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

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

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

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

    (1le nle 200;2le mle 10^5;1le t_ile 2;1le y_i le m.)

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

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

    讲解

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

    思路一

    假设我们什么结论都没有得出来,考虑直接 ( t 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_ige1,A_iin N^+)),小数部分为 (B_i(0le B_i<1))

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

    显然有 (j_1*A_i<j_2*B_i,lceil j_1*B_i ceillelceil j_2*B_i ceil)

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

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

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

    坑点

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

    • ( t 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;
    }
    
  • 相关阅读:
    如何实现一个教师与学生教学辅助平台?
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    2..移动APP开发使用什么样的原型设计工具比较合适?
    new delete和malloc free的区别
    char * 和char[]的区别以及怎样与string类型进行转换
    浅谈const的基本用法
    c++ map按key或value的值分别进行排序
    二叉树及先序,中序,后序遍历
    c++发展趋势
    markdown 的基本操作
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14729149.html
Copyright © 2020-2023  润新知