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
题目描述
运行代码
#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
思路:
- 首先,使用两个循环将
C
和D
数组初始化为 0。for(int i=0;i<=m;++i) C[i]=D[i]=0;
- 然后,填充第一项的系数。通过一个循环,将幂次在
a[1]
到b[1]
范围内的系数设置为 1。for(int i=a[1];i<=b[1];++i) C[i]=1;
- 从第二项开始进行迭代计算。对于每一项:通过两层嵌套的循环计算新的系数,并累加到
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!
题目描述
运行代码
#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
思路:
- 首先,使用
memset
函数将C
和D
数组初始化为 0 。memset(C, 0, sizeof(C)); memset(D, 0, sizeof(D));
- 接着,为
C
数组填充初始值。对于幂次从 0 到a[1]
的位置,将系数设置为 1 。for (int i = 0; i <= a[1]; ++i) C[i] = 1;
- 然后,从第 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
。