P2261 [CQOI2007] 余数求和(整除分块)、HDU2152——Fruit、HDU1085——Holding Bin-Laden Captive!(构造生成函数)

17 篇文章 0 订阅

P2261 [CQOI2007] 余数求和(整除分块)

题目描述

G33 整除分块(数论分块) - 董晓 - 博客园 (cnblogs.com)

运行代码

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long LL;

LL calculate(LL k, LL l, LL r) {
    return (k / l) * (r - l + 1) * (l + r) / 2;
}

int main() {
    LL n, k, l = 1, r, res;
    scanf("%lld%lld", &n, &k);
    res = n * k;
    while (l <= n) {
        if (k / l == 0) {
            break;
        }
        r = min(k / (k / l), n);
        res -= calculate(k, l, r);
        l = r + 1;
    }
    printf("%lld", res);
    return 0;
}

代码思路

整体逻辑:程序的主要目的是根据输入的两个整数 n 和 k 计算一个最终的结果 res 。首先,将 res 初始化为 n * k 。

循环部分:通过一个 while 循环来逐步计算并调整 res 的值。在每次循环中,首先判断 k / l 是否为 0,如果是则跳出循环。计算 r 的值,r 为 min(k / (k / l), n) ,用于确定本次计算的范围。调用自定义函数 calculate 计算一个中间值,并从 res 中减去这个值。然后更新 l 的值为 r + 1 ,准备下一次循环。

自定义函数 calculate:这个函数用于根据给定的参数 k 、l 、r 进行特定的数学计算,返回计算结果。

HDU2152——Fruit

题目描述

Problem - 2152 (hdu.edu.cn)

运行代码

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

int n, m;
int a[110], b[110];  // 存幂次
int C[110], D[210];  // 存系数

int calc() {
    memset(C, 0, sizeof(C));
    memset(D, 0, sizeof(D));

    // 填充第 1 项的系数
    for (int i = a[1]; i <= b[1]; ++i) C[i] = 1;

    // 从第 2 项开始枚举
    for (int i = 2; i <= n; ++i) {
        // 计算 x^(j + k) 的系数
        for (int j = 0; j <= m; ++j) {
            for (int k = a[i]; k <= b[i]; ++k) {
                D[j + k] += C[j];
            }
        }

        // 转存 C,清空 D
        memcpy(C, D, sizeof(C));
        memset(D, 0, sizeof(D));
    }

    return C[m];
}

int main() {
    while (~scanf("%d%d", &n, &m)) {
        for (int i = 1; i <= n; ++i) scanf("%d%d", &a[i], &b[i]);
        printf("%d\n", calc());
    }
    return 0;
}

代码思路

函数 calc 思路

  1. 首先,使用两个循环将 C 和 D 数组初始化为 0。for(int i=0;i<=m;++i) C[i]=D[i]=0;
  2. 然后,填充第一项的系数。通过一个循环,将幂次在 a[1] 到 b[1] 范围内的系数设置为 1。for(int i=a[1];i<=b[1];++i) C[i]=1;
  3. 从第二项开始进行迭代计算。对于每一项:通过两层嵌套的循环计算新的系数,并累加到 D 数组中。外层循环遍历当前已有的系数位置 j,内层循环遍历当前项的幂次范围 k,将对应的系数累加。for(int j=0;j<=m;++j) for(int k=a[i];k<=b[i];++k) D[j+k]+=C[j];之后,将 D 数组的内容复制到 C 数组,并清空 D 数组,为下一次迭代做准备。for(int j=0;j<=m;++j) C[j]=D[j], D[j]=0;

主函数 main 思路:不断读取输入的 n 和 m 的值,以及每一项的幂次范围 a[i] 和 b[i] 。然后调用 calc 函数计算并输出特定幂次 m 的系数。

HDU1085——Holding Bin-Laden Captive!

题目描述

Problem - 1085 (hdu.edu.cn)

运行代码

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

int n, a[4], b[4], C[8005], D[8005];

void calc(int m) {
    memset(C, 0, sizeof(C));
    memset(D, 0, sizeof(D));

    for (int i = 0; i <= a[1]; ++i) C[i] = 1;

    for (int i = 2; i <= 3; ++i) {
        for (int j = 0; j <= m; ++j) {
            for (int k = 0; k <= a[i] * b[i] && j + k <= m; k += b[i]) {
                D[j + k] += C[j];
            }
        }

        memcpy(C, D, sizeof(C));
        memset(D, 0, sizeof(D));
    }
}

int main() {
    while (scanf("%d%d%d", &a[1], &a[2], &a[3]) && (a[1] || a[2] || a[3])) {
        b[2] = 2;
        b[3] = 5;
        int m = a[1] * 1 + a[2] * 2 + a[3] * 5;
        calc(m);
        int x = 0;
        while (x <= m && C[x]) x++;
        printf("%d\n", x);
    }
    return 0;
}

代码思路

函数 calc 思路

  1. 首先,使用 memset 函数将 C 和 D 数组初始化为 0 。memset(C, 0, sizeof(C)); memset(D, 0, sizeof(D));
  2. 接着,为 C 数组填充初始值。对于幂次从 0 到 a[1] 的位置,将系数设置为 1 。for (int i = 0; i <= a[1]; ++i) C[i] = 1;
  3. 然后,从第 2 项到第 3 项进行迭代计算。对于每一项:通过三层嵌套的循环计算新的系数,并累加到 D 数组中。外层循环遍历当前可能的系数位置 j,中层循环控制迭代次数,内层循环按照一定的步长 b[i] 累加系数。最后,将 D 数组的内容复制到 C 数组,并清空 D 数组,为下一次迭代做准备。memcpy(C, D, sizeof(C)); memset(D, 0, sizeof(D));

主函数 main 思路

不断读取输入的 a[1]a[2] 和 a[3] 的值,只要其中至少有一个不为 0 ,就继续执行后续操作。

设定 b[2] = 2 和 b[3] = 5 。根据输入计算 m 的值,m = a[1] * 1 + a[2] * 2 + a[3] * 5 。

调用 calc 函数进行计算。从 0 开始遍历 C 数组,找到第一个系数为 0 的位置 x ,并输出 x 。

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱姌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值