首页 > 其他分享 >洛谷解题日记||基础篇4

洛谷解题日记||基础篇4

时间:2024-11-12 18:16:30浏览次数:3  
标签:洛谷 数列 int mid long 解题 include 配料 日记

 

#include <iostream>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;

    // 计算所有矩形的数量
    long long totalRectangles = (long long)(n * (n + 1) / 2) * (long long)(m * (m + 1) / 2);
    
    // 计算正方形的数量
    long long totalSquares = 0;
    int maxSize = min(n, m);
    for (int size = 1; size <= maxSize; ++size) {
        totalSquares += (long long)(n - size + 1) * (long long)(m - size + 1);
    }

    // 计算长方形的数量
    long long totalRectanglesOnly = totalRectangles - totalSquares;

    // 输出正方形和长方形的数量
    cout << totalSquares << " " << totalRectanglesOnly << endl;

    return 0;
}

 


 

思路

  1. 问题抽象: 这是一个典型的“背包问题”的变种,其中我们有10个配料,每个配料的质量只能是 1、2 或 3,总和要等于给定的美味程度 nnn。我们需要找出所有可能的组合,并且按字典序输出这些组合。

  2. 如何生成所有组合

    • 每个配料的质量范围是 1 到 3,我们可以使用递归(或回溯算法)来生成所有的组合。
    • 递归的每一步,试图给第 iii 种配料分配 1、2 或 3 克,递归处理下一个配料,直到所有配料的质量总和为 nnn。
  3. 字典序要求

    • 由于递归是从第1种配料开始逐步分配,因此可以保证在递归过程中,输出的组合已经是按字典序排列的。
  4. 结束条件

    • 当配料的总质量等于 nnn 时,记录这个组合。
    • 如果总质量超过 nnn,则返回并尝试其他可能的分配。
  5. 剪枝

    • 如果当前的总质量已经超过 nnn,就可以直接停止递归。

解决方案

使用回溯算法来生成所有合法的组合。具体步骤如下:

  1. 递归函数:从第 1 种配料开始分配质量,尝试 1、2 或 3 克,并递归计算后续配料的组合。
  2. 终止条件:如果所有配料的总质量等于 nnn,则记录该组合。
  3. 输出:最终输出所有的组合的数量,并逐一输出这些组合。

#include <iostream>
#include <vector>
using namespace std;

int n;  // 美味程度
vector<int> current(10, 0);  // 当前的配料组合
vector<vector<int>> results;  // 保存所有符合条件的组合

// 递归回溯函数
void backtrack(int index, int sum) {
    if (index == 10) {  // 如果已经分配了所有10种配料
        if (sum == n) {  // 如果总和等于n,记录当前组合
            results.push_back(current);
        }
        return;
    }
    
    // 试图给第index种配料分配1、2、3克
    for (int i = 1; i <= 3; ++i) {
        if (sum + i <= n) {  // 如果当前总和不超过n
            current[index] = i;  // 设置当前配料的质量
            backtrack(index + 1, sum + i);  // 递归处理下一个配料
        }
    }
}

int main() {
    cin >> n;  // 输入美味程度n
    
    backtrack(0, 0);  // 从第1种配料开始,初始总和为0
    
    // 输出结果
    cout << results.size() << endl;  // 输出组合数量
    for (const auto& combo : results) {
        for (int i = 0; i < 10; ++i) {
            cout << combo[i] << " ";  // 输出每种配料的质量
        }
        cout << endl;
    }

    return 0;
}


求解步骤

  1. 二分法求解月利率

    • 我们的目标是找到一个月利率 r,使得在给定 w0 和 w 的条件下,贷款在 m 个月后刚好还清。
    • 用二分法搜索 r 的范围 [0, 3](假设最大利率不超过 300% / 12 = 25% 每月)。
  2. 模拟贷款偿还过程

    • 对于给定的 r,我们需要模拟从第 1 个月到第 m 个月的贷款余额,检查总余额是否与初始贷款金额相符。
  3. 精度要求

    • 利率要四舍五入到小数点后一位。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

// 输入的贷款金额 m、每月还款金额 y、总还款月数 t
double m, y, s;
int t;

// 输出结果的函数,k 是计算得到的月利率
int out(double k)
{
    printf("%.1f", k * 100); // 输出月利率 k,按百分比输出(乘以100)
    exit(0);  // 输出结果后退出程序
}

// 递归函数,二分法寻找合适的月利率
void solve(double l, double r)
{
    double k = (l + r) / 2;  // 计算区间中点
    double u = r - l;  // 当前区间长度
    double a = m;  // 初始贷款余额
    
    // 如果区间已经足够小,精度达到了要求,输出当前的中点利率
    if (u < 0.0001) out(k);
    
    // 计算偿还过程:每月都按利率更新贷款余额
    for (int i = 1; i <= t; i++) {
        a = a * (1 + k) - y;  // 贷款余额更新:利率按复利方式计算,每月减去还款金额
    }
    
    // 如果贷款余额仍大于0,说明当前利率过低,需要增大利率,递归继续在左半区间查找
    if (a > 0) solve(l, k);
    // 如果贷款余额小于0,说明当前利率过高,需要减小利率,递归继续在右半区间查找
    if (a < 0) solve(k, r);
    // 如果贷款余额刚好为0,表示找到合适的利率,直接输出
    if (a == 0) out(k);
}

int main()
{
    // 输入贷款金额 m、每月还款金额 y、还款月数 t
    cin >> m >> y >> t;
    
    // 调用 solve 函数,设置初始的二分法区间为 [0, 5](月利率范围从 0 到 500%)
    solve(0, 5);
}

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 判断是否可以将数列分成 M 段,每段的和不超过 maxSum
bool canSplit(const vector<int>& A, int M, long long maxSum) {
    int count = 1;          // 当前段数,初始为 1 段
    long long currentSum = 0;  // 当前段的和
    for (int num : A) {
        // 如果加入当前数会使得当前段的和超过 maxSum,则需要开始一个新段
        if (currentSum + num > maxSum) {
            count++;         // 增加段数
            currentSum = num; // 新段的和从当前数开始
            // 如果段数超过 M,则不能在 maxSum 下分成 M 段,返回 false
            if (count > M) {
                return false;
            }
        } else {
            // 否则将当前数加入当前段的和中
            currentSum += num;
        }
    }
    // 如果段数不超过 M,说明在 maxSum 下可以分成 M 段,返回 true
    return true;
}

int main() {
    int N, M;
    cin >> N >> M;           // 读取数列长度 N 和分段数 M
    vector<int> A(N);        // 存储数列 A
    long long sum = 0, maxElem = 0; // sum 用于存储数列总和,maxElem 用于存储数列中的最大值

    // 读取数列,同时计算数列的总和 sum 和数列的最大值 maxElem
    for (int i = 0; i < N; ++i) {
        cin >> A[i];
        sum += A[i];
        maxElem = max(maxElem, (long long)A[i]);
    }
    
    // 二分搜索范围为 [maxElem, sum]
    long long left = maxElem, right = sum;
    while (left < right) {
        long long mid = left + (right - left) / 2; // 计算中间值 mid,作为候选的每段和的最大值
        if (canSplit(A, M, mid)) {
            // 如果可以在 maxSum = mid 下分成 M 段,那么尝试更小的最大和,右边界左移
            right = mid;
        } else {
            // 如果不可以,则 mid 太小,左边界右移
            left = mid + 1;
        }
    }
    
    // 当 left == right 时即为我们要求的最小的每段和的最大值
    cout << left << endl;
    return 0;
}

解释

  • 二分搜索范围确定left 从数列的最大值开始,因为单段的和不能小于任何一个单独元素。right 从数列的总和开始,因为将所有元素放在一段内,其和就是总和。

  • 二分核心逻辑

    • 在二分的过程中,通过中间值 mid 检查是否可以分成 M 段且每段和不超过 mid
    • 如果可以,则尝试更小的 mid,以找到更小的每段和的最大值;如果不行,增大 mid 值。
  • 贪心的 canSplit 函数:从左到右遍历数列,将元素累加到当前段,直到段和超出 maxSum 时重新开始一段,计数段数。最终判断段数是否符合要求。

这样每次迭代都可以将可能的最大和范围缩小,最终找到符合要求的最小可能值。

标签:洛谷,数列,int,mid,long,解题,include,配料,日记
From: https://blog.csdn.net/ke_wu/article/details/143697392

相关文章

  • 【题解】洛谷P8346:最澄澈的空与海
    【题解】洛谷P8346:最澄澈的空与海猜结论题,本身其实很简单,在纸上画个差不多就能想出来,我一开始想二分图最大匹配,但是还是太大了,不可以。当一个二分图有且仅有一种解时,必定有节点的入度为\(1\)。我们想到有多种匹配的情况,可以想到如果这是一个环的情况,一个左边的点将他右边的点......
  • 题解:洛谷 P5180 【模板】支配树
    在图论模拟赛被T4的有向图必经点硬控了\(10^9+7s\),写篇题解纪念一下。其实,求有向图的必经点,通法就是支配树。一些定义:支配点:在确定起点\(S\)的情况下,对于一个点\(k\),若存在\(x\),使得删除\(x\)以及与\(x\)连接的边后,\(x\)与\(k\),不再强连通,那么就称\(k\)为\(x......
  • 【题解】洛谷P3118: Moovie Mooving G
    洛谷P3118:MoovieMoovingG看到数据范围考虑状压,题目要求看的电影最少那就维护时间最大,我们设\(f_{i}\)为\(i\)状态最多可以看多久的电影,对于不在集合的点我们枚举转移。我们每个开始时间都对应一个截至时间,问能加入这个点,每个点花费时间是固定的,我们又要不间断所以我们找......
  • 【日记】居然把今天的应酬逃掉了(668 字)
    正文今天副行长回来了。本来以为今晚又要应酬,结果跑掉了。嘿嘿。有一个企业的董事长听说他回来了,所以嚷嚷着要请客。而客户请吃饭的对象又只有客户经理,所以我和柜面主管两个人就溜了。办公室的人也没去。不过明天是全行内部性质的,估计溜不了了。能逃一次是一次吧,嘿嘿,果......
  • 洛谷P5744
    P5744【深基7.习9】培训-洛谷|计算机科学教育新生态【深基7.习9】培训题目描述某培训机构的学员有如下信息:-姓名(字符串)-年龄(周岁,整数)-去年NOIP成绩(整数,且保证是5 的倍数)经过为期一年的培训,所有同学的成绩都有所提高,提升了20%(当然NOIP满分是600 分,不能......
  • 洛谷P1618
    P1618三连击(升级版)-洛谷|计算机科学教育新生态三连击(升级版)题目描述将1,2,...9共9个数分成三组,分别组成三个三位数,且使这三个三位数的比例是A:B:C,试求出所有满足条件的三个三位数,若无解,输出`No!!!`。//感谢黄小U饮品完善题意输入格式三个数,A,B,C。输出格式......
  • CSP-J2024 复赛T1(洛谷P11227)题解
    前传作者初赛没过。坐标sd,79分过不了已经适应了。话说这次泄题事件闹得沸沸扬扬,都说各省分数线要降,最后sd降了8分,80。挺逆天的,感觉sd再这样下去一点OIer都要没了。思路桶排思想,用二维数组模拟一整副牌,本来做的时候是怕有重复牌才这样做,事实上不会。ACCode#include<bits/......
  • 洛谷题单103数组题解||by红糖
    P1428小鱼比可爱题目描述人比人,气死人;鱼比鱼,难死鱼。小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度。参赛的鱼被从左到右排成一排,头都朝向左边,然后每只鱼会得到一个整数数值,表示这只鱼的可爱程度,很显然整数越大,表示这只鱼越可爱,而且任意两只鱼的可爱程度可能一样......
  • wsl2踩坑日记(配置代理/zsh+p10k/Neovim)
    1.proxywsl--installUbuntu-24.04安装好wsl之后,测试了一下v2rayN的代理能不能正常使用(用vultr服务器搭建的校园网ipv6免流),发现可以curlwww.google.com,但是sudoapt-getupdate报错Clearsignedfileisn'tvalid,got'NOSPLIT'(doesthenetworkrequireauthe......
  • 洛谷题单指南-二叉堆与树状数组-P2085 最小函数值
    原题链接:https://www.luogu.com.cn/problem/P2085题意解读:有n个函数,函数中x取值>=1,计算所有函数能得到的值中最小的m个。解题思路:函数中x取值是>=1的整数,因此每个函数的值是f(1),f(2),f(3)....,是一个递增序列,题目本质上是要从n个递增序列中找到前m个最小的数。首先,对所有函数......