做题笔记

题目

1.倍数个数

请问在 10000(含)到 90000(含)中,有多少个数是 128 的倍数。

从L~R 有多少个数,满足XX条件?可以直接遍历,也可以用前缀。

定义一个sum[]数组,sum[i]储存从1i有多少个数满足XX条件(从1i有多少个数是128的倍数,直接用i/128),最后用sum[R]-sum[L-1]。

2.年份计数

2021 是一个特殊的年份,它的千位和十位相同,个位比百位多一。请问从 1000(含) 到 9999(含) 有多少个这样的年份?

循环,枚举从1000~9999的所有年份,然后获取该年份的各个位数上的数字,进行判断,比较。

获取X个位上的数字,X%10

获取X十位上的数字,X/10%10

获取X百位上的数字,X/100%10

以此类推。

3.排列计数

如果 1到 n 的一个排列中,所有奇数都在原来的位置上,称为一个奇不动排列。
例如,1 到 7 的排列 (1,6,3,4,5,2,7) 是一个奇不动排列,因为 1,3,5,7 都在原来的位置上。
请问,1 到 21 的所有排列中,有多少个奇不动排列。

奇不动排列:1 _ 3 _ 5 _ 7 _ ... _ 21 奇数位置不动,偶数任意排列,答案就是偶数个数的阶乘。

4.节节高升

小蓝要上一个楼梯,共 15 级台阶。
小蓝每步可以上 1 级台阶,也可以上 2 级、3 级或 4 级,再多就没办法一步走到了。
每级台阶上有一个数值,可能正也可能负。每次走到一级台阶上,小蓝的得分就加上这级台阶上的数值。
台阶上的数值依次为:1,2,1,1,1,1,5,5,4,−1,−1,−2,−3,−1,−9。
小蓝希望不超过 6 步走到台阶顶端,请问他得分的最大值是多少?
注意,小蓝开始站在地面上,地面没有分值。他最终要走到台阶顶端,所以最终一定会走到数值为 −9 的那级台阶,所以 −9 一定会加到得分里面。

递归或者动态规划,动态转移方程 f(stair + i, step - 1) + a[stair-1] stair 目前在哪一级。step 目前剩下几步。

5.数递增三元组

在数列α[1],a[2],……. ,a[n] 中,如果对于下标i,j,k满足0<i<j<k<n+1且a[i]<a[j]<a[k],则称a[i],a[j],a[k]为一组递增三元组。
请问对于下面的长度为20的数列,有多少个递增三元组?
2,9,17,4,14,10,25,26,11,14,16,17,14,21,16,27,32,20,26,36。

使用三重循环从小到大遍历,然后进行判断。

6.人字排列

一个 1 到 n 的排列被称为人字排列,是指排列中的第 11 到第 (+1)/2(n+1)/2 个元素单调递增,第 (+1)/2(n+1)/2 到第 n 个元素单调递减。
例如:(2,3,5,8,9,7,6,4,1) 是一个人字排列,而 (1,2,3) 和 (2,1,3) 都不是人字排列,(2,4,3) 也不是一个人字排列(它甚至不是一个 1 到 4的排列)。
请问,1到 n 的排列中有多少个人字排列?

人字排列就是最大的字在中间,然后最大值左边的数递增,右边的数递减,所以中间的字就确定了,这时候只需要确定左边的数字,右边的数字自然就确定了。所以只用求左边的数字有多少种组合。当n为奇数时,最大值左边有(n-1)/2个位置,当n为偶数时,最大值左边有n/2-1,综合起来就是⌊(n-1)/2⌋。也就是在剩下的n-1个数里再挑⌊(n-1)/2⌋。所以就有image-20230204223719135

计算组合数可以使用杨辉三角

img

	int c[1001][1001]
	c[1][0] = c[1][1] = 1;
	for (int i = 2; i < n; i++)
	{
		c[i][0] = 1;
		for (int j = 1; j <= i; j++)
		{
			c[i][j] = (c[i - 1][j - 1] + c[i - 1][j])%1000000007;//
		}
	}//矩阵储存,第一行只有一个1,可以直接赋值

需要在计算杨辉三角的时候就进行求模,不然数据会超过int类型。

7.设计方案

小蓝给出了教学楼的平面图,用一个n行m列的01矩阵表示,其中0表示空地,1表示教学楼。两个相邻的1 (上下相邻或左右相邻)之间互相可达。请帮小蓝检查一下,是否教学楼的任意两个地方都可以连通到其它地方。
输入描述
输入的第一行包含两个整数n, m,用一个空格分隔。接下来n行,每行一个长度为m的01串,表示教学楼的平面图。
输出描述
如果满足要求,输出"YES",否则输出"NO"”,请注意字母全部都是大写。

使用深度优先搜索,,二维字符数组存储01串,输入时注意用getchar消除回车,或直接使用cin进行输入,并且记录'1'的数量,搜索的时候判断是否存在上、下、左、右的位置,并且根据bool类型的vs数组判断是否去过,没去过,而且数值为'1'就继续访问,访问到一个就计数,最后与输入时记录的数量比较。

8.2021公约数

如果一个整数g能同时整除整数A和B,则称g是A和B的公约数。例如:43是86和2021的公约数。
请问在1(含)到2021(含)中,有多少个数与2021存在大于1的公约数。请注意2021和2021有大于1的公约数,因此在计算的时候要算一个。

辗转相除法

int gcd(int a, int b)
{
	if (b == 0) return a;
	return gcd(b, a % b);   
}
int main()
{
	int cnt = 0;
	for (int i = 1; i <= 2021; i++)
	{
		if (gcd(i, 2021) > 1)
			cnt++;
	}
	printf("%d", cnt);
}

9.数字三角形

如图数字三角形。如下所示为一个数字三角形。请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和。
   
1. 一步可沿左斜线向下或右斜线向下走;
2. 三角形行数小于等于 100;
3. 三角形中的数字为 0,1,…,99;
    
测试数据通过键盘逐行输入。

如上例数据应以样例所示格式输入:

数字三角形。从最下面网上递推,

dsBuffer.bmp

int a[101][101];
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= i; j++)
			cin >> a[i][j];
	}
	for (int i = n - 1; i >= 0; i--)
	{
		for (int j = 0; j <= i; j++)
		{
			if (a[i + 1][j] >= a[i + 1][j + 1])
				a[i][j] += a[i + 1][j];         //处理
			else
				a[i][j] += a[i + 1][j + 1];

		}
	}
	cout << a[0][0] << endl;
}

10.组合型枚举

输入n,m,在n个中选m个,找出所有方案

int n;//共计N个数
int m;//选m个数
vector<int> chosen;
void calc(int x) {
    if (chosen.size() > m || chosen.size() + (n - x + 1) < m) //剪枝
        return;
    if (x == n + 1) { //选够了m个数输出
        for (int i = 0; i < chosen.size(); i++)
            printf("%d ", chosen[i]);
            //也可以不输出,存放起来也是可以的,主要是看题目。
        puts("");
        return;
    }
    calc(x + 1);
    chosen.push_back(x);
    calc(x + 1);
    chosen.pop_back();//消除痕迹
}
int main()
{
    cin>>n>>m;
     calc(1);
}

11.排列型枚举

求n个元素的全排列

int n; //共计N个数
int order[20];
bool chosen[20];
void calc(int k)
{
	if (k == n + 1)
	{
		for (int i = 1; i <= n; i++)
			cout << order[i] << " ";

		puts("");

		return;
	}
	for (int i = 1; i <= n; i++)
	{
		if (chosen[i])
			continue;
		order[k] = i;
		chosen[i] = 1;
		calc(k + 1);
		chosen[i] = 0;
		order[k] = 0;
	}
}
int main()
{
	cin >> n;
	calc(1);
}

12.差分

//读入原始数据 n,m,a

输入n,m

for(int i=1;i<=n;i++){
    
    输入a[i]
}

//差分
for(int i=1;i<=n;i++)
    
    b[i]=a[i]-a[i-1] 

//区间操作
while(m--)
{
    输入l,r,value
    b[l]+value
    b[r+1]-value
}

//前缀和还原
for(int i=1;i<n;i++)
    
    b[i]=b[i]+b[i-1] 

13.前缀和

输 入 N 和 M 

输入 N 个值 并计算前缀和
for( int i=1;i<=N;i++)
    输入a[i]
    并计算sum[i]=sum[i-1]+a[i]

输入 M 个区间,计算结果

while(M)
    M-=1
    输入 L , R
    计算 [r]-[l-1],并输出

14.选择排序

void select_Sort(int* a, int len)
{
	for (int i = 0; i < len; i++)
	{
		int k = i;
		for (int j = i + 1; j < len; j++)
		{
			if (a[j] < a[k]) k = j;
		}
		if (k != i) swap(a[i], a[k]);
	}
}
int main()
{

	int a[] = { 5 ,4 ,6 ,8 ,7, 1, 2 ,3 };
	select_Sort(a, 8);
	for (auto i : a) cout << i << " ";

}

swap是交换函数

15.冒泡排序

#include <iostream>
using namespace std;

void BubbleSort(int arr[], int n)
{
    for(int i = 0; i < n - 1; i++)
    {
        for(int j = 0; j < n - i - 1; j++)
        {
            if(arr[j] > arr[j+1])
               swap(arr[j],arr[j+1]);
        }
    }
}

int main ()
{

    int a[6] = {4, 5, 6, 1, 2, 3};
    BubbleSort(a,6);
    for(auto i: a) cout<<i<<" ";

}

16.桶排序

int maxN=10; //题目出现的数据的最大值
int a[maxN];
int n;
cin>>n

for(int i=0;i<n;i++)
{
    int key;
    cin>>key;
    a[key]++;
 
}

for(int i=0;i<maxN;i++)
{
    for(int j=0;j<a[i];j++)
    {
        cout<<i<<" ";
    }
}

17.插入排序


#include <iostream>
#include <stack>
using namespace std;

void insert_Sort(int *a,int len)
{
    for (int i=0; i<len; i++)
    {
        int x = a[i];
        int j = i - 1;
        while( j>=0&&x < a[j])
        {
            a[j + 1] = a[j];
            j -= 1;
        }
        a[j + 1] = x;
    }
}

int main ()
{

    int a[9] = {0, 3, 2, 4, 1, 6, 5, 2, 7};
    insert_Sort(a,9);
    for(auto i: a) cout<<i<<" ";

}

18.二分查找

// 在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (low < high)
{
    int mid = (low + high) / 2;
    if (a[mid] >= x)
        high = mid;

    else
        low = mid + 1;
}

// 在单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while (low < high)
{
    int mid = (low + high + 1) / 2;

    if (a[mid] <= x)
        low = mid;

    else
        high = mid - 1;
}

19.实数的二分查找

//模版一:实数域二分,设置eps法
//令 eps 为小于题目精度一个数即可。比如题目说保留4位小数,0.0001 这种的。那么 eps 就可以设置为五位小数的任意一个数 0.00001- 0.00009 等等都可以。
//一般为了保证精度我们选取精度/100 的那个小数,即设置 eps= 0.0001/100 =1e-6
while (l + eps < r)
{
    double mid = (l + r) / 2;
    if (pd(mid))
        r = mid;
    else
        l = mid;
}

//模版二:实数域二分,规定循环次数法
//通过循环一定次数达到精度要求,这个一般 log2N < 精度即可。N 为循环次数,在不超过时间复杂度的情况下,可以选择给 N 乘一个系数使得精度更高。
    for (int i = 0; i < 100; i++)
{
    double mid = (l + r) / 2;
    if (pd(mid))
        r = mid;
    else
        l = mid;
}
posted @   盐酸氟西汀  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示