循环结构(入门3)

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)错误。

  • 堆空间:通过动态内存分配(例如 newmalloc)分配的内存位于堆上,堆的大小通常比栈大,可以处理更大的数据结构。

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 字节),而栈的默认大小可能不足以分配这么大的数组。

  • 堆内存:如果使用 newmalloc 动态分配内存,数组会在堆上分配,堆空间一般比栈大得多,因此可以容纳更大的数组。例如,你可以使用 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