#6556. 2026/4/24/ZYS课堂笔记

2026/4/24/ZYS课堂笔记

一、日期计算:累计天数函数

1. 问题描述

给定日期 (y, m, d),计算从 公元1年1月1日 到该日期的总天数(不含1年1月1日当天)。

2. 完整代码(修正语法错误版)

#include<bits/stdc++.h>
#define int long long
using namespace std;

// 判断闰年:能被4整除但不能被100整除,或能被400整除
bool is_leap(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

// 计算从1年1月1日到 (y,m,d) 的总天数
int js(int y, int m, int d) {
    int ans = 0;
    
    // 1. 累加完整年份的天数
    for (int year = 1; year < y; year++) {
        ans += is_leap(year) ? 366 : 365;
    }
    
    // 2. 累加当前年完整月份的天数
    int days_in_month[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
    if (is_leap(y)) days_in_month[2] = 29; // 闰年2月+1天
    for (int month = 1; month < m; month++) {
        ans += days_in_month[month];
    }
    
    // 3. 累加当前月的天数(不含当天)
    ans += d - 1;
    return ans;
}

signed main() {
    // 示例:计算2026-04-24的总天数
    cout << js(2026, 4, 24) << endl;
    return 0;
}

3. 关键点解析

  • 闰年判断(year%4==0 && year%100!=0) || (year%400==0)
  • 效率优化:原代码用 while 循环逐年累加,可优化为数学公式(如 365*(y-1) + (y-1)/4 - (y-1)/100 + (y-1)/400),避免循环。
  • 语法修正:原代码中 yue == 3 5 7 8 10 12 需改为 yue == 3 || yue == 5 || ...(逻辑或连接)。

二、递推与取模:防止数据溢出

1. 问题背景

递推公式:f[i] = f[i-1] + 2*f[i-2],初始条件 f[0]=1, f[1]=1,求 f[n] % 1e9(因数据增长极快,需取模防止溢出)。

2. 代码片段与解析

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M = 1e9;
const int N = 1e5 + 10; // 假设n的范围

int f[N];

signed main() {
    int n; cin >> n;
    f[0] = 1;
    f[1] = 1;
    for (int i = 2; i <= n; i++) {
        f[i] = (f[i-1] + 2 * f[i-2]) % M; // 每步取模,防止溢出
    }
    cout << f[n] << endl;
    return 0;
}

3. 取模运算核心性质

  • (a + b) % mod = [(a % mod) + (b % mod)] % mod
  • (a * b) % mod = [(a % mod) * (b % mod)] % mod
  • 意义:每步取模可将数据控制在 mod 范围内,避免 long long 溢出。

三、贪心算法:出租车最少费用计算

1. 题目规则

  • 前4km:10元(2.5元/km)
  • 4~8km:2元/km(性价比最高)
  • 超过8km:2.4元/km
  • 目标:给定路程 n,求最少费用。

2. 完整代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

// 计算路程lc的最少费用
double js(int lc) {
    if (lc == 0) return 0;
    if (lc <= 4) return 10;
    if (lc <= 8) return 10 + 2 * (lc - 4);
    
    int full_8 = lc / 8; // 完整8km的段数
    int remain = lc % 8;  // 剩余路程
    double ans = full_8 * 18; // 每8km费用18元(10+2*4)
    
    // 贪心策略:剩余路程<=4km时,按2.4元/km补;否则单独跑一段
    if (remain <= 4) ans += 2.4 * remain;
    else ans += 10 + 2 * (remain - 4);
    return ans;
}

signed main() {
    int n;
    while (cin >> n && n != 0) {
        double ans = js(n);
        if (ans == (int)ans) cout << (int)ans << endl;
        else printf("%.1lf\n", ans);
    }
    return 0;
}

3. 贪心策略解析

  • 性价比分析:前8km平均费用 18/8 = 2.25元/km(最优),因此优先按8km分段。
  • 余数处理
    • 剩余 <=4km:按2.4元/km补(比单独跑一段更便宜);
    • 剩余 >4km:单独跑一段(10元起步+2元/km)。

四、基础语法:数组与sort函数

1. 卡牌交换问题思路

  • 若两副卡牌的数字频率完全相同,可通过“交换位置”变得一模一样;
  • 本质:用数组统计每个数字的出现次数,比较频率数组是否一致。

2. sort函数用法演示

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

int main() {
    int a[10] = {5, 2, 8, 1, 9};
    
    // sort(起始地址, 结束地址+1)
    sort(a, a + 5); // 对前5个元素排序(下标0~4)
    for (int i = 0; i < 5; i++) cout << a[i] << " "; // 输出:1 2 5 8 9
    cout << endl;
    
    // 数组名的含义:数组首地址
    cout << "数组首地址:" << a << endl;
    cout << "第二个元素地址:" << a + 1 << endl;
    return 0;
}

3. 关键点

  • sort参数:左闭右开区间 [start, end),因此结束地址需+1;