P5719 【深基4.例3】分类平均
题目描述
给定 nn 和 kk,将从 1 到 nn 之间的所有正整数可以分为两类:A 类数可以被 kk 整除(也就是说是 kk 的倍数),而 B 类数不能。请输出这两类数的平均数,精确到小数点后 11 位,用空格隔开。
数据保证两类数的个数都不会是 00。
输入格式
输入两个正整数 nn 与 kk。
输出格式
输出一行,两个实数,分别表示 A 类数与 B 类数的平均数。精确到小数点后一位。
输入输出样例
输入 #1
100 16
输出 #1
56.0 50.1
说明/提示
数据保证,1≤n≤100001≤n≤10000,1≤k≤1001≤k≤100。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n, k;
cin >> n >> k;
int A = 0;
int B = 0;
int count = 0;
for (int i = 1; i <= n; i++) {
if (i % k == 0) {
A += i;
count++;
}
else B += i;
}
cout << fixed<<setprecision(1) << (double)A / count << " " << (double)B / (n - count) << endl;
return 0;
}
注意:
保留一位有效数字,别忘记把A和B强制转换为double类型的数据
【深基4.例4】一尺之棰
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a;
cin >> a;
int day = 1;
while (a != 1) {
a /= 2;
day++;
}
cout << day << endl;
return 0;
}
注意点:
day从1开始,不是0,至少也要一天
【深基4.例6】数字直角三角形
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n;
cin >> n;
int count = n;
int sum = 0;
for (int i = 1; i <= (n * n + n) / 2; i++) {
if (sum == count) {
cout << endl;
count--;
sum = 0;
}
if (i < 10)cout << "0" << i;
else cout << i;
sum++;
}
return 0;
}
[NOIP1998 普及组] 阶乘之和
#include <iostream>
#include <iomanip>
using namespace std;
int multiply[101] = { 0 };
int sum[101] = { 0 };
//计算阶乘
void multiplyBy(int x)
{
int g = 0;
for (int i = 100; i >= 0; i--) {
multiply[i] = multiply[i] * x + g;
g = multiply[i] / 10;
multiply[i] = multiply[i] % 10;
}
}
//计算阶乘的和
void accumulate()
{
int g = 0;
for (int i = 100; i >= 0; i--) {
sum[i] = sum[i] + multiply[i] + g;
g = sum[i] / 10;
sum[i] = sum[i] % 10;
}
}
void printSum()
{
int i;
for (i = 0; i < 101; i++) {
if (sum[i] != 0)break;
}
for (int j = i; j < 101; j++) {
cout << sum[j];
}
cout << endl;
}
int main()
{
int n;
cin >> n;
multiply[100] = 1;
sum[100] = 1;
for (int i = 2; i <= n; i++) {
multiplyBy(i);
accumulate();
}
printSum();
return 0;
}
[NOIP2013 普及组] 计数问题
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n, x;
cin >> n >> x;
int count = 0;
int temp, y;
for (int i = 1; i <= n; i++) {
temp = i;
while (temp) {
y = temp % 10;
temp /= 10;
if (y == x)count++;
}
}
cout << count << endl;
return 0;
}
注意:
逐位检查
[NOIP2002 普及组] 级数求和
#include <iostream>
#include <string>
using namespace std;
int main()
{
double k;
cin >> k;
double s = 1.0;
int n = 2;
while (s <= k) {
s += double(1.0 / n);
if (s <= k)n++;
}
cout << n << endl;
return 0;
}
注意点:
有可能s在加完之后就大于k了,所以n++之前要加一个判断条件
[NOIP2015 普及组] 金币
#include <iostream>
#include <string>
using namespace std;
int main()
{
int k;
cin >> k;
int i, j, day = 0;
int sum = 0;
for (i = 1; i <= k; i++) {
if (day == k)break;
j = i;
while (j--) {
sum += i;
day++;
if (day == k)break;
}
}
cout << sum << endl;
return 0;
}
【深基4.例13】质数口袋
#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool f[10000005];
long long prime[200005];
int main()
{
for (long long i = 2; i <= 1000005; i++) {
if (!f[i]) {
f[i] = 1;
for (long long j = i + i; j <= 1000005; j += i) {
f[j] = 1;
}
prime[++prime[0]] = i;
}
}
long long k; int cnt = 0;
int sum = 0;
cin >> k;
for (int i = 1; i <= prime[0]; i++)
{
if (sum+prime[i] <= k) {
sum += prime[i];
cout << prime[i] << endl;
cnt++;
}
else {
break;
}
}
cout << cnt << endl;
return 0;
}
注意:
如果把bool f[10000005];long long prime[200005];这两行代码放到main函数中的话就会报错,
原因:
1. 栈空间 vs 堆空间
在 C++ 中,数组的默认分配方式决定了它们是在 栈(stack)上分配还是在 堆(heap)上分配:
-
栈空间:局部变量(包括局部数组)默认在栈上分配。栈的大小通常比堆小,可能在不同的系统中有所不同。栈上分配的内存通常有较严格的大小限制,超过一定大小时,程序可能会出现栈溢出(stack overflow)错误。
-
堆空间:通过动态内存分配(例如
new
或malloc
)分配的内存位于堆上,堆的大小通常比栈大,可以处理更大的数据结构。
2. 具体到我的代码
当数组定义为全局变量时:
bool f[10000005]; // 全局变量
long long prime[200005]; // 全局变量
- 这两个数组是 全局变量,存储在 数据段(data segment)中,而不是栈上。
- 数据段通常用于存储全局变量、静态变量以及常量等。它不受栈大小限制,因此可以存储较大的数组。
当数组定义为局部变量时:
int main() {
bool f[10000005]; // 局部变量
long long prime[200005]; // 局部变量
...
}
- 这些数组是 局部变量,默认分配在 栈 上。如果你定义一个过大的数组,栈空间可能不足以容纳它,尤其是在数组大小很大的时候(例如
f[10000005]
和prime[200005]
)。 - 栈的大小限制因编译器、操作系统等因素而异,通常情况下,栈空间的限制要小于堆空间,因此当你在
main
函数中定义这么大的局部数组时,程序可能会因栈溢出而崩溃。
3. 栈溢出与内存分配
-
栈溢出:当你定义了一个非常大的局部数组时,栈可能不够用,导致程序崩溃。比如你在栈上定义了一个
bool f[10000005]
数组,这个数组需要约 10 MB 的内存(每个bool
占 1 字节),而栈的默认大小可能不足以分配这么大的数组。 -
堆内存:如果使用
new
或malloc
动态分配内存,数组会在堆上分配,堆空间一般比栈大得多,因此可以容纳更大的数组。例如,你可以使用vector<bool>
或vector<long long>
来代替静态数组,这样就可以避免栈溢出的问题。
4. 为什么全局变量不报错
全局变量的内存分配方式与局部变量不同,它们不存储在栈中,而是存储在数据段或 BSS 段,因此对于非常大的数组,通常不会遇到栈溢出的问题。
解决:
1,把这两个数组定义到全局函数中
2,,使用Vector去定义
[USACO1.5] 回文质数 Prime Palindromes
#include <iostream>
#include <vector>
#include <cmath>
#include <string>
using namespace std;
//判断一个数字是否为回文数字
bool isPalindrome(int num)
{
string str = to_string(num);
int i = 0, j = str.length() - 1;
while (i < j) {
if (str[i] != str[j])return false;
i++;
j--;
}
return true;
}
//普通埃拉托斯特尼筛法,找到2~sqrt(b)之间所有的质数
void seive(int limit, vector<int>& primes)
{
vector<bool>isPrime(limit + 1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= limit; i++) {
if (isPrime[i]) {
primes.push_back(i);
for (int j = i * i; j <= limit; j += i) {
isPrime[j] = false;
}
}
}
}
//分段筛法,找出[low,high]之间的质数
void segmentedSeive(int low, int high)
{
int limit = sqrt(high) + 1;
vector<int>primes;
seive(limit, primes);
vector<bool>isPrime(high - low + 1, true);
for (int p : primes)
{
int start = max(p * p, (low + p - 1) / p * p);
for (int j = start; j <= high; j += p)
{
isPrime[j - low] = false;
}
}
//输出[low,high]之间所有的质数
for (int i = 0; i <= high - low; i++) {
if (isPrime[i] && (low + i) >= 2 && isPalindrome(low + i)) {
cout << low + i << endl;
}
}
}
int main()
{
int a, b;
cin >> a >> b;
segmentedSeive(a, b);
return 0;
}
小玉在游泳
#include <iostream>
#include <vector>
#include <cmath>
#include <string>
using namespace std;
int main()
{
double s;
cin >> s;
int count = 0;
double sum = 0.0;
for (int i = 0; sum < s; i++) {
sum += 2 * pow(0.98, i);
count++;
}
cout << count << endl;
return 0;
}
[NOIP2011 普及组] 数字反转
#include <iostream>
using namespace std;
int main()
{
int n, s = 0;
cin >> n;
while (n) {
s = s * 10 + n % 10;
n /= 10;
}
cout << s << endl;
return 0;
}
月落乌啼算钱(斐波那契数列)
方法1:
由于这个是斐波那契数列,所以可以直接用for循环求出每一项(前两项之和)
#include <iostream>
using namespace std;
long long a = 1, b = 1, c=0;
int main()
{
int n;
cin >> n;
for (int i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
cout << c << ".00" << endl;
return 0;
}
方法2:
直接使用题目给出的公式
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n;
cin >> n;
double p1 = pow(5, 0.5);
double p2 = pow((1 + p1) / 2, n) - pow((1 - p1) / 2, n);
long long f = p2 / p1;
cout << f << ".00" << endl;
return 0;
}
【深基4.习5】求极差 / 最大跨度值
#include <iostream>
#include <cmath>
using namespace std;
int M = 1;
int m = 10001;
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int a;
cin >> a;
if (M < a)M = a;
if (m > a)m = a;
}
cout << M - m << endl;
return 0;
}
最长连号
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
int count = 0;
int result = 0;
vector<int>arr(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
for (int i = 0; i < n-1; i++) {
if (arr[i + 1 ]- arr[i] == 1)count++;
else count = 0;
if (count > result)result = count;
}
cout << result + 1 << endl;
return 0;
}
[NOIP2012 普及组] 质因数分解
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
bool isPrime(int num)
{
for (int i = 2; i < sqrt(num); i++) {
if (num % i == 0)return false;
}
return true;
}
int main()
{
int n;
cin >> n;
for (int i = 2; i < n; i++) {
if (n % i == 0) {
int j = n / i;
if (isPrime(i) && isPrime(j)) {
cout << max(i, j) << endl;
break;
}
}
}
return 0;
}
注意:
isPrime函数中的for循环中,循环条件要写 i < sqrt(num);,而不是i<num,这样会超时
【深基4.习8】求三角形
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
int count = 0;
//打印正方形
for (int i = 1; i <= n * n; i++) {
if (count == n) {
count = 0;
cout << endl;
}
if (i < 10)cout << "0" << i;
else cout << i;
count++;
}
count = 0;
cout << endl << endl;
//打印三角形
int j;
int x = 1;
for (int i = 1; i <= n; i++) {
for (j = 1; j <= n - i; j++) {
cout << " ";
count++;
}
for (int k = 1; j <= n; j++) {
if (x < 10) cout << "0" << x;
else cout << x;
count++;
x++;
if (count == n) {
cout << endl;
count = 0;
}
}
}
return 0;
}
【深基4.习9】打分
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int M = -1;
int m = 11;
int sum = 0;
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
if (M < x)M = x;
if (m > x)m = x;
sum += x;
}
sum = sum - M - m;
cout <<fixed<<setprecision(2)<< 1.0*sum / (n - 2)<< endl;
return 0;
}
[COCI2017-2018#6] Davor
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int main()
{
int n;
cin >> n;
int k, x;
bool flag = true;
for (k = 1; flag; k++) {
for (x = 1; x <= 100; x++) {
if (7 * x + 21 * k == n / 52) {
flag = false;
break;
}
}
}
cout << x << endl << k-1 << endl;
return 0;
}
注意:
注意最后输出的时候k-1,因为循环一轮之后k++,所以要-1
[NOIP2004 提高组] 津津的储蓄计划
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
int main()
{
int i, sum = 0, x, leave = 0;
for (i = 1; i <= 12; i++) {
cin >> x;
if (leave + 300 - x >= 100) {
sum += (leave + 300 - x) / 100 * 100;
leave = (leave + 300 - x) % 100;
}
else if (leave + 300 - x < 0) {
cout << "-" << i << endl;
break;
}
else {
leave += 300 - x;
}
}
if (i == 13)cout << sum * 1.2 + leave << endl;
return 0;
}
注意:
最后的总钱数,需要加上leave