半个月总结
文章目录
写的题:
递归
递归是一种解决问题的方法,其中一个函数通过不断调用自身来解决规模较小的子问题。递归通常涉及两个部分:基本情况和递归关系。
递归的思想过程:
- 基本情况(Base Case): 这是递归函数中最简单、最基础的情况。通常,基本情况是一个问题规模足够小以直接解决的情况,而无需继续递归。
- 递归关系(Recursive Relation): 这是递归函数的核心。在递归关系中,问题被分解成规模较小的子问题,并通过递归调用来解决这些子问题。递归关系必须能够使问题逐渐趋于基本情况。
- 递归调用: 在递归关系中,函数会调用自身,解决规模较小的子问题。这是递归的关键点。
写递归函数技巧
注意:函数中只需要列出两种情况
1.基本情况
2.找关系式表示n
【深基7.习8】猴子吃桃
题目描述
一只小猴买了若干个桃子。第一天他刚好吃了这些桃子的一半,又贪嘴多吃了一个;接下来的每一天它都会吃剩余的桃子的一半外加一个。第 n n n 天早上起来一看,只剩下 1 1 1 个桃子了。请问小猴买了几个桃子?
输入格式
输入一个正整数 n n n,表示天数。
输出格式
输出小猴买了多少个桃子。
样例 #1
样例输入 #1
4
样例输出 #1
22
提示
数据保证, 1 ≤ n ≤ 20 1\le n\le20 1≤n≤20。
主要代码:
int amount(int n){
if(n==1){
return 1;
}else{
return (amount(n-1)+1)*2; //here
}
}
P5739 【深基7.例7】计算阶乘
斐波那契数列
int fibonacci(int n) {
if (n <= 1) {
return n;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
洛谷
有意思的题
P5739 【深基7.例7】计算阶乘
题目描述
求 n ! n! n!,也就是 1 × 2 × 3 ⋯ × n 1\times2\times3\dots\times n 1×2×3⋯×n。
挑战:尝试不使用循环语句(for、while)完成这个任务。
输入格式
第一行输入一个正整数 n n n。
输出格式
输出一个正整数,表示 n ! n! n!。
样例 #1
样例输入 #1
3
样例输出 #1
6
提示
数据保证, 1 ≤ n ≤ 12 1 \leq n\le12 1≤n≤12。
有意思的地方:
挑战:尝试不使用循环语句(for、while)完成这个任务。
那么就有蛮多种解法
递归
#include <stdio.h>
int multiple(int n){
if(n==0) return 1;
return n*multiple(n-1);//不断调用函数
}
//n*(n-1)*(n-2)*...*1
int main(){
int n;
scanf("%d",&n);
int sum=multiple(n);
printf("%d",sum);
return 0;
}
直接printf
#include <stdio.h>
int main(){
int a[12]={1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600};
int n;
scanf("%d",&n);
int sum=a[n-1];
printf("%d",sum);
return 0;
}
超多个if
include <stdio.h>
int main(){
return 0;
}
[USACO1.5] 回文质数 Prime Palindromes
USACO1.5] 回文质数 Prime Palindromes - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
因为 151 151 151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151 151 151 是回文质数。
写一个程序来找出范围 [ a , b ] ( 5 ≤ a < b ≤ 100 , 000 , 000 ) [a,b] (5 \le a < b \le 100,000,000) [a,b](5≤a<b≤100,000,000)(一亿)间的所有回文质数。
输入格式
第一行输入两个正整数 a a a 和 b b b。
输出格式
输出一个回文质数的列表,一行一个。
样例 #1
样例输入 #1
5 500
样例输出 #1
5
7
11
101
131
151
181
191
313
353
373
383
提示
Hint 1: Generate the palindromes and see if they are prime.
提示 1: 找出所有的回文数再判断它们是不是质数(素数).
Hint 2: Generate palindromes by combining digits properly. You might need more than one of the loops like below.
提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。
题目翻译来自NOCOW。
USACO Training Section 1.5
产生长度为 5 5 5 的回文数:
for (d1 = 1; d1 <= 9; d1+=2) { // 只有奇数才会是素数
for (d2 = 0; d2 <= 9; d2++) {
for (d3 = 0; d3 <= 9; d3++) {
palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
}
}
}
分析:
我一开始没看到说明提示这一部分,所以纯按照我自己的理解处理这道题的话
1.写个函数判断是否是素数
2.写个函数判断是否是回文数
3.总和条件判断输出
其中判断是否是回文数相较下来有点动脑(没看提示的话)
一开始自己写的代码:
回文数部分采用数组元素比较处理
先将待处理数每一位存入数组
然后用a[i],a[size-i-1]
判断位置对称的两个数是否相等“
但这样写会超时
就当提供了一种思路吧
#include <stdio.h>
#include <math.h>
int a[100000000];
int sushu(int n){
int i;
for(i=2;i<=sqrt(n);i++){
if(n%i==0) return 0;
}
return 1;
}
int huiwen(int n){
int i=0;
while(n!=0){
a[i++]=n%10;
n/=10;
}
int size=i;
for(i=0;i<size/2;i++){
if(a[i]!=a[size-i-1]) return 0;
}
return 1;
}
int main(){
int a,b;
scanf("%d %d",&a,&b);
int i;
for(i=a;i<=b;i++){
if(huiwen(i)&&sushu(i)) printf("%d\n",i);
}
return 0;
}
AC代码:
就照做提示部分就好
将数倒置然后再和原来的数比较
#include <stdio.h>
#include <math.h>
int sushu(int n){
int i;
for(i=2;i<=sqrt(n);i++){
if(n%i==0) return 0;
}
return 1;
}
int is_palindrome(int n) {
int reversed = 0, original = n;
while (n > 0) {
reversed = reversed * 10 + (n % 10);
n /= 10;
}
return (original == reversed);
}
int main() {
int a, b;
scanf("%d %d", &a, &b);
for (int i = a; i <= b; i++) {
if (is_palindrome(i) && sushu(i)) {
printf("%d\n", i);
}
}
return 0;
}
赦免战俘
P5461 赦免战俘 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目背景
借助反作弊系统,一些在月赛有抄袭作弊行为的选手被抓出来了!
题目描述
现有 2 n × 2 n ( n ≤ 10 ) 2^n\times 2^n (n\le10) 2n×2n(n≤10) 名作弊者站成一个正方形方阵等候 kkksc03 的发落。kkksc03 决定赦免一些作弊者。他将正方形矩阵均分为 4 个更小的正方形矩阵,每个更小的矩阵的边长是原矩阵的一半。其中左上角那一个矩阵的所有作弊者都将得到赦免,剩下 3 个小矩阵中,每一个矩阵继续分为 4 个更小的矩阵,然后通过同样的方式赦免作弊者……直到矩阵无法再分下去为止。所有没有被赦免的作弊者都将被处以棕名处罚。
给出 n n n,请输出每名作弊者的命运,其中 0 代表被赦免,1 代表不被赦免。
输入格式
一个整数 n n n。
输出格式
2 n × 2 n 2^n \times 2^n 2n×2n 的 01 矩阵,代表每个人是否被赦免。数字之间有一个空格。
样例 #1
样例输入 #1
3
样例输出 #1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 1 1
0 0 0 0 0 1 0 1
0 0 0 0 1 1 1 1
0 0 0 1 0 0 0 1
0 0 1 1 0 0 1 1
0 1 0 1 0 1 0 1
1 1 1 1 1 1 1 1
分析:
这道题的意思就是将一个二维数组切成四块,左上那一块全部赋值为0,然后将四块每一块继续切四块,左上继续赋值为0
从这就能看出要用到递归
最最最主要就是找到每一次的左上部分
然后利用递归不断切分
直至切分部分只剩下一个数
注意:
为了方便赋值,先将二维数组全赋值为0
左上部分需要变为0的先处理为1
方便写代码
代码:
#include <stdio.h>
#include <math.h>
#define N 2005 //定义的大一些,定义2的10次方会越界
int n;
int a[N][N]={0};
void Dfs(int x,int y,int xx,int yy){
if(x==xx||y==yy) return;
int tx=(x+xx)/2,ty=(y+yy)/2;
int i,j;
for(i=x;i<=tx;i++){
for(j=y;j<=ty;j++){
a[i][j]=1; //先找到将要变为0的元素,赋值为1
}
}
Dfs(x,ty+1,tx,yy);
Dfs(tx+1,y,xx,ty);
Dfs(tx+1,ty+1,xx,yy); //继续切分
}
int main(){
int x;
scanf("%d",&x);
n=pow(2,x);
Dfs(1,1,n,n);
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%d%c",a[i][j]?0:1,j==n?'\n':' ');
}
}
return 0;
}
统计方形(数据加强版)
题目背景
1997年普及组第一题
题目描述
有一个 n × m n \times m n×m 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。
输入格式
一行,两个正整数 n , m n,m n,m( n ≤ 5000 , m ≤ 5000 n \leq 5000,m \leq 5000 n≤5000,m≤5000)。*
输出格式
一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。
样例 #1
样例输入 #1
2 3
样例输出 #1
8 10
大佬的思考过程 P2241 统计方形(数据加强版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
更细致的过程
代码:
#include<stdio.h>
int main() {
int n, m, rec = 0, sqr = 0;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (i == j)
sqr += (n - i) * (m - j);
else
rec += (n - i) * (m - j);
}
}
printf("%d %d\n", sqr, rec);
return 0;
}
集合求和
题目描述
给定一个集合 s s s(集合元素数量 ≤ 30 \le 30 ≤30),求出此集合所有子集元素之和。
输入格式
集合中的元素(元素 ≤ 1000 \le 1000 ≤1000)
输出格式
s s s 所有子集元素之和。
样例 #1
样例输入 #1
2 3
样例输出 #1
10
提示
【样例解释】
子集为: ∅ , { 2 } , { 3 } , { 2 , 3 } \varnothing, \{ 2 \}, \{ 3 \}, \{ 2, 3 \} ∅,{2},{3},{2,3},和为 2 + 3 + 2 + 3 = 10 2 + 3 + 2 + 3 = 10 2+3+2+3=10。
【数据范围】
对于 100 % 100 \% 100% 的数据, 1 ≤ ∣ s ∣ ≤ 30 1 \le \lvert s \rvert \le 30 1≤∣s∣≤30, 1 ≤ s i ≤ 1000 1 \le s_i \le 1000 1≤si≤1000, s s s 所有子集元素之和 ≤ 10 18 \le {10}^{18} ≤1018。
注意数据类型为long long
分析过程:
代码:
#include <stdio.h>
#include <math.h>
#define N 100010
long long a[N];
long long sum=0;
long long total=0;
int main() {
int i = 0;
int cnt=0;
while (scanf("%lld", &a[++cnt]) == 1);
for (i = 1; i < cnt; i++) {
sum += a[i];
}
long long num = (long long)pow(2,cnt-2);
long long total = sum * num;
printf("%lld\n", total);
return 0;
}