P1008 [NOIP 1998 普及组] 三连击
# P1008 [NOIP 1998 普及组] 三连击
## 题目背景
本题为提交答案题,您可以写程序或手算在本机上算出答案后,直接提交答案文本,也可提交答案生成程序。
## 题目描述
将 $1, 2, \ldots , 9$ 共 $9$ 个数分成 $3$ 组,分别组成 $3$ 个三位数,且使这 $3$ 个三位数构成 $1 : 2 : 3$ 的比例,试求出所有满足条件的 $3$ 个三位数。
## 输入格式
无
## 输出格式
若干行,每行 $3$ 个数字。按照每行第 $1$ 个数字升序排列。
## 输入输出样例 #1
### 输入 #1
```
无
```
### 输出 #1
```
192 384 576
* * *
...
* * *
(剩余部分不予展示)
```
## 说明/提示
NOIP1998 普及组 第一题
#include<bits/stdc++.h>
int main(){int a,b,c;for(a=123;a<=333;a++){b=a*2;c=a*3;if((a/100+a/10%10+a%10+b/100+b/10%10+b%10+c/100+c/10%10+c%10==1+2+3+4+5+6+7+8+9)&&((a/100)*(a/10%10)*(a%10)*(b/100)*(b/10%10)*(b%10)*(c/100)*(c/10%10)*(c%10)==(1)*(2)*(3)*(4)*(5)*(6)*(7)*(8)*(9)))printf("%d %d %d\n",a,b,c);}return 0;
}
P1009 [NOIP 1998 普及组] 阶乘之和
# P1009 [NOIP 1998 普及组] 阶乘之和
## 题目描述
用高精度计算出 $S = 1! + 2! + 3! + \cdots + n!$($n \le 50$)。
其中 `!` 表示阶乘,定义为 $n!=n\times (n-1)\times (n-2)\times \cdots \times 1$。例如,$5! = 5 \times 4 \times 3 \times 2 \times 1=120$。
## 输入格式
一个正整数 $n$。
## 输出格式
一个正整数 $S$,表示计算结果。
## 输入输出样例 #1
### 输入 #1
```
3
```
### 输出 #1
```
9
```
## 说明/提示
**【数据范围】**
对于 $100 \%$ 的数据,$1 \le n \le 50$。
**【其他说明】**
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 $n \le 20$,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
NOIP1998 普及组 第二题
#include<iostream>
#include<cstring>
using namespace std;
int n,a[90],b[90],c[90],f[90],d=0,len_a,len_b=1,len_c=1,len_ans,m=1;
string s;
int main(){cin>>n;b[0]=1; //初始化for(int i=1;i<=n;i++){ //计算i的阶乘,已经算好了i-1的阶乘len_a=0; //i的长度int p=i;while(p>0){ //把i存进a数组a[len_a++]=p%10;p/=10;}for(int j=0;j<len_a;j++) //计算a*b(i*(i-1)的阶乘),即i的阶乘,看不懂的网上查,我也不知道为什么for(int k=0;k<=len_b;k++)c[j+k]+=a[j]*b[k];for(int j=0;j<len_c;j++) //需要进位的就进位if(c[j]>9) c[j+1]+=c[j]/10,c[j]%=10;if(c[len_c]) len_c++; //看最高位要不要进位len_ans=len_b,len_b=len_c,m=max(m,len_c); //把len_b赋值给len_ans,修改len_b的值,m为i阶乘的长度,看有没有进位for(int k=len_c-1;k>=0;k--) b[k]=c[k]; //把c存进b数组,即存进i的阶乘,下次循环b为i-1的阶乘len_c=len_a+len_ans;memset(c,0,sizeof(c)); //清零c数组,准备计算下个阶乘for(int j=0;j<m;j++){ //高精加,直接套模板f[j]+=b[j];if(f[j]>9) f[j+1]+=f[j]/10,f[j]%=10; //进位,注意不要写成f[j+1]++,f[j]-=10;就因为这里wa了一个点}}while(!f[m]&&m>0) m--; //去掉首导零for(int i=m;i>=0;i--) cout<<f[i]; //倒序输出return 0;
}
P1014 [NOIP 1999 普及组] Cantor 表
# P1014 [NOIP 1999 普及组] Cantor 表
## 题目描述
现代数学的著名证明之一是 Georg Cantor 证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

我们以 Z 字形给上表的每一项编号。第一项是 $1/1$,然后是 $1/2$,$2/1$,$3/1$,$2/2$,…
## 输入格式
整数$N$($1 \leq N \leq 10^7$)。
## 输出格式
表中的第 $N$ 项。
## 输入输出样例 #1
### 输入 #1
#include <bits/stdc++.h>
using namespace std;
int main() {int n,k=1;cin>>n;while (n>k) {n=n-k;k++;}if(k%2==0) cout<<n<<"/"<<(k+1-n);else cout<<k+1-n<<"/"<<n;return 0;
}
```
7
```
### 输出 #1
```
1/4
```
## 说明/提示
- 2024-11-18 0:30 数据中加入了样例,放在不计分的子任务 2 中。
P1044 [NOIP 2003 普及组] 栈
# P1044 [NOIP 2003 普及组] 栈
## 题目背景
栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。
栈有两种最重要的操作,即 pop(从栈顶弹出一个元素)和 push(将一个元素进栈)。
栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。
## 题目描述

宁宁考虑的是这样一个问题:一个操作数序列,$1,2,\ldots ,n$(图示为 1 到 3 的情况),栈 A 的深度大于 $n$。
现在可以进行两种操作,
1. 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
2. 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由 `1 2 3` 生成序列 `2 3 1` 的过程。

(原始状态如上图所示)
你的程序将对给定的 $n$,计算并输出由操作数序列 $1,2,\ldots,n$ 经过操作可能得到的输出序列的总数。
## 输入格式
输入文件只含一个整数 $n$($1 \leq n \leq 18$)。
## 输出格式
输出文件只有一行,即可能输出序列的总数目。
## 输入输出样例 #1
### 输入 #1
```
3
```
### 输出 #1
```
5
```
## 说明/提示
**【题目来源】**
NOIP 2003 普及组第三题
//递归转递推 递推做法
#include<cstdio>
#define MAX_N 20
#define ll long long
using namespace std;
int n;
ll f[MAX_N][MAX_N];
int main()
{scanf("%d",&n);for(int i=0;i<=n;i++){f[0][i]=1;}for(int i=1;i<=n;i++){for(int j=i;j<=n;j++){if(i==j)f[i][j]=f[i-1][j];else f[i][j]=f[i][j-1]+f[i-1][j];}}printf("%lld",f[n][n]);return 0;
}
# P1024 [NOIP 2001 提高组] 一元三次方程求解
## 题目描述
有形如:$a x^3 + b x^2 + c x + d = 0$ 这样的一个一元三次方程。给出该方程中各项的系数($a,b,c,d$ 均为实数),并约定该方程存在三个不同实根(根的范围在 $-100$ 至 $100$ 之间),且根与根之差的绝对值 $\ge 1$。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 $2$ 位。
提示:记方程 $f(x) = 0$,若存在 $2$ 个数 $x_1$ 和 $x_2$,且 $x_1 < x_2$,$f(x_1) \times f(x_2) < 0$,则在 $(x_1, x_2)$ 之间一定有一个根。
## 输入格式
一行,$4$ 个实数 $a, b, c, d$。
## 输出格式
一行,$3$ 个实根,从小到大输出,并精确到小数点后 $2$ 位。
## 输入输出样例 #1
### 输入 #1
```
1 -5 -4 20
```
### 输出 #1
```
-2.00 2.00 5.00
```
## 说明/提示
**【题目来源】**
NOIP 2001 提高组第一题
#include<cstdio>
double a,b,c,d;
double fc(double x)
{return a*x*x*x+b*x*x+c*x+d;
}
int main()
{double l,r,m,x1,x2;int s=0,i;scanf("%lf%lf%lf%lf",&a,&b,&c,&d); //输入for (i=-100;i<100;i++){l=i; r=i+1;x1=fc(l); x2=fc(r);if(!x1) {printf("%.2lf ",l); s++;} //判断左端点,是零点直接输出。//不能判断右端点,会重复。if(x1*x2<0) //区间内有根。{while(r-l>=0.001) //二分控制精度。{m=(l+r)/2; //middleif(fc(m)*fc(r)<=0) l=m; else r=m; //计算中点处函数值缩小区间。}printf("%.2lf ",r); //输出右端点。s++;}if (s==3) break; //找到三个就退出大概会省一点时间}return 0;
}