目录
1.题目:空间
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝准备用 256MB256MB 的内存空间开一个数组,数组的每个元素都是 3232 位 二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256MB256MB 的空间可以存储多少个 3232 位二进制整数?
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
题解:
#include <stdio.h>
int main(void)
{
// 1 MB = 1024 KB
// 1 KB = 1024 Byte
// 1 Byte = 8 bit
long long count = 0;
count = (256 * 1024 * 1024) / 4;
printf("%lld",count);
return 0;
}
2.题目:砝码称重
问题描述
你有一架天平和 NN 个砝码,这 NN 个砝码重量依次是 W1,W2,⋅⋅⋅,WNW1,W2,⋅⋅⋅,WN。
请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 NN。
第二行包含 NN 个整数:W1,W2,W3,⋅⋅⋅,WNW1,W2,W3,⋅⋅⋅,WN。
输出格式
输出一个整数代表答案。
样例输入
3
1 4 6
样例输出
10
样例说明
能称出的 1010 种重量是:1、2、3、4、5、6、7、9、10、111、2、3、4、5、6、7、9、10、11。
1=1;1=1;
2=6−4(2=6−4(天平一边放 66,另一边放 4);4);
3=4−1;3=4−1;
4=4;4=4;
5=6−1;5=6−1;
6=6;6=6;
7=1+6;7=1+6;
9=4+6−1;9=4+6−1;
10=4+6;10=4+6;
11=1+4+6。11=1+4+6。
评测用例规模与约定
对于 5050的评测用例,1≤N≤151≤N≤15。
对于所有评测用例,1≤N≤100,N1≤N≤100,N个砝码总重不超过 100000100000。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
题解:(动态规划)
#include<stdio.h>
#include<math.h>
int d[101][100001]={0};
int main(){
int n;
d[0][0]=1;
int a[105];
scanf("%d",&n);
int su=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
su+=a[i];
for(int j=0;j<=su;j++)
if(d[i-1][j]){
d[i][j]=1;
d[i][abs(j-a[i])]=1;
d[i][j+a[i]]=1;
}
}
int sum=0;
for(int i=1;i<=su;i++){
if(d[n][i])
sum++;
}
printf("%d",sum);
}
3.题目:直线
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z(x,y)∣0≤x<2,0≤y<3,x∈Z,y∈Z,即横坐标 是 00 到 11 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数 的点。这些点一共确定了 11 条不同的直线。
给定平面上 20×2120×21 个整点 (x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z(x,y)∣0≤x<20,0≤y<21,x∈Z,y∈Z,即横 坐标是 00 到 1919 (包含 00 和 1919) 之间的整数、纵坐标是 00 到 2020 (包含 00 和 2020) 之 间的整数的点。
请问这些点一共确定了多少条不同的直线。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
题解:
#include <stdio.h>
#include <stdlib.h>
int n = 0;
double ab[100000][2]={{0},{0}};
int fun(int x0,int y0,int x1,int y1)
{
double a = (y0-y1)*1.0/(x0-x1);
double b = (x0*y1-x1*y0)*1.0/(x0-x1);
for(int i=0;i<n;i++)
{
if(ab[i][0]==a&&ab[i][1]==b) return 0;
}
ab[n][0] = a;
ab[n][1] = b;
n++;
return 1;
}
int main(int argc, char *argv[])
{
for(int x0=0;x0<20;x0++)
for(int y0=0;y0<21;y0++)
{
for(int x1 = x0+1;x1<20;x1++)
for(int y1 = y0+1;y1<21;y1++)
fun(x0,y0,x1,y1);
}
printf("%d",2*n+41);
return 0;
}
//答案是2n+41,其中41是与x轴或y轴平行的直线 其余的直线使用暴力法求解, for(int x0=0;x0<20;x0++) for(int y0=0;y0<21;y0++) {
//两点确定一条直线,第一个点的所有取值 for(int x1 = x0+1;x1<20;x1++) for(int y1 = y0+1;y1<21;y1++) fun(x0,y0,x1,y1); }
//第二个点的所有取值,由于第二个点在第一个点的右上方,确定的直线斜率均为正值,
//斜率是负数的所有直线都有与之对称的斜率为正数的直线,这也是答案n2的原因。
//nt fun(int x0,int y0,int x1,int y1) 参数是两个点 { double a = (y0-y1)1.0/(x0-x1);
//求斜率 double b = (x0y1-x1*y0)1.0/(x0-x1); 求截距 for(int i=0;i<n;i++) n是已确定直线的个数,
//将新求得的直线与已知直线比对 { if(ab[i][0]==a&&ab[i][1]==b) return 0;
//如果斜率和截距相同,那么该直线已经被确定过了,下一个点。 } 代码继续执行, ab[n][0] = a;
//说明是一条新的直线,存入第n+1条直线的斜率是a。 ab[n][1] = b; 截距是b n++; 直线数目更新 return 1; } printf("%d",2n+41);
4.题目:时间显示
题目描述
小蓝要和朋友合作开发一个时间显示的网站。
在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 19701970 年 11 月 11 日 00:00:0000:00:00 到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
输入描述
输入一行包含一个整数,表示时间。
输出描述
输出时分秒表示的当前时间,格式形如 HH:MM:SS
,其中 HH
表示时,值为 00 到 2323,MM
表示分,值为 00 到 5959,SS
表示秒,值为 00 到 5959。时、分、秒 不足两位时补前导 00。
输入输出样例
示例 1
输入
46800999
输出
13:00:00
示例 2
输入
1618708103123
输出
01:08:23
评测用例规模与约定
对于所有评测用例,给定的时间为不超过 10181018 的正整数。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
题解:
提示:1秒=1000毫秒
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
long long n,a;
int m,f,s;
scanf("%lld",&n);
a=n/1000;
m=a%60;
a=a/60;
f=a%60;
a=a/60;
s=a%24;
printf("%02d:%02d:%02d",s,f,m);
return 0;
}
5.题目:括号序列(未写出)
题目描述
给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
例如,对于括号序列 ((()(((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()()()()、()(())()(())、(())()(())()、(()())(()()) 和 ((()))((()))。
输入描述
输入一行包含一个字符串 s,表示给定的括号序列,序列中只有左括号和右括号。
输出描述
输出一个整数表示答案,答案可能很大,请输出答案除以 10000000071000000007 (即 109+7)109+7) 的余数。
输入输出样例
示例 1
输入
((()
输出
5
评测用例规模与约定
对于 4040 的评测用例,∣s∣≤200∣s∣≤200。
对于所有评测用例,1≤∣s∣≤50001≤∣s∣≤5000。
运行限制
- 最大运行时间:5s
- 最大运行内存: 512M
6.题目:杨辉三角形
题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列: 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,⋯
给定一个正整数 NN,请你输出数列中第一次出现 NN 是在第几个数?
输入描述
输入一个整数 NN。
输出描述
输出一个整数代表答案。
输入输出样例
示例 1
输入
6
输出
13
评测用例规模与约定
对于 2020 的评测用例,1≤N≤101≤N≤10; 对于所有评测用例,1≤N≤10000000001≤N≤1000000000。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
题解:
1.(暴力,只能对一个案例)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int a[100][100],i,j,k,t;
a[0][0]=1;
a[1][0]=1;a[1][1]=1;
for(i=2;i<100;i++)
{a[i][0]=1;a[i][i]=1;
for(j=1;j<i;j++)
a[i][j]=a[i-1][j]+a[i-1][j-1];
}
scanf("%d",&k);
for(i=0;i<100;i++)
{for(j=0;j<=i;j++)
{if(k==a[i][j])
{t=1;
printf("%d",(i+1)*i/2+j+1);
break;
}
}
if(t==1)
break;
}// 请在此输入您的代码
return 0;
}
2.
//解题思路:
//1、首先通过画图,发现杨辉三角对称,而题目要求找到数 n 最早出现的位置,
//那么我们可以确定,n最早出现的位置一定在左半边,而且最中间的是该行最大的数
//通过图,我们可以发现通过行和列的枚举是不好的,看数据1e9也就是十亿,
//2.这是个很大的工程,因此我们试想可不可以从斜行来观察呢??
//下图我们可以观察到,第1斜行的1=C(0,0),第二斜行的2=C(2,1),第三斜行的6=C(4,2),第四斜行的20=C(6,3)…
//也就是说,如果我设共 i 斜行,那么第 i 斜行的第一个数为C(2*i,i),同时它是该斜行中最小的数字
//那么我们一定可以找到1e9的位置
//3.1e9的位置确定:
//显然C(32,16)< 1e9,而C(34,17)> 1e9,因此我们可以对前16行进行枚举
//4.枚举顺序:
//首先对于左半边杨辉三角来说,每行最大的数一定出现在该行末尾,同时它也是该数最早出现的位置
//因此我们不妨从第16斜行开始枚举,只要出现等于 n 的数直接返回位置即可
//对于查找,我们可以对每个斜行采用二分的方法查找n
//对于位置,我们可以在查找的时候确定,n所在行 r(不是斜行)和所在斜行 k ,
//然后通过等差公式 r*(r+1)/2 计算它之前数目的个数再加上 k+1
//例如:n = 20 (由于推到,第一行行号为 0 ,斜行行号也是 0)
//查找过程我们可以确定20在第7行,实际返回 r = 6 ,在第 4 斜行 ,但此时 k 是 3,因此 k+1
//结果 ans = 6*7/2 + 3 + 1 = 25
//5.时间复杂度的计算:
//枚举16斜行 --> O(16)
//二分查找 --> O(logn)
//综合起来,算法时间复杂度为 O(16logn)
#include<stdio.h>
#include<stdlib.h>
#define ll long long
int n;
int max(int a,int b)
{
return a>b?a:b;
}
ll C(int a,int b)//计算二项式C(a,b)
{
ll res=1;
int i,j;
for(i=a,j=1;j<=b;i--,j++)
{
res=res*i/j;
if(res>n)
{
return res;//如果大于n已经无意义了,因为斜行是递增的
}
}
return res;
}
int check(int k)
{
//二分该斜行,找到大于等于该值的第一个数
//左边界2k,右边界max(n,l),避免右边界小于左边界
int l=2*k,r=max(n,l);
while(l<r)
{
int mid=(l+r)/2;
if(C(mid,k)>=n) r=mid;
else l=mid+1;
}
if(C(r,k)!=n)
{
return 0;
}
printf("%lld",(ll)(r+1)*r/2+k+1);
return 1;
}
int main()
{
scanf("%d",&n);
int i;
//从第16斜行枚举
for(i=16; ;i--)
{
if(check(i)==1)
{
break;
}
}
return 0;
}
7.题目:双向排序
题目描述
给定序列 (a1,a2,⋅⋅⋅,an)=(1,2,⋅⋅⋅,n)(a1,a2,⋅⋅⋅,an)=(1,2,⋅⋅⋅,n),即 ai=iai=i。
小蓝将对这个序列进行 mm 次操作,每次可能是将 a1,a2,⋯ ,aqia1,a2,⋯,aqi 降序排列,或者将 aqi,aqi+1,⋯ ,anaqi,aqi+1,⋯,an 升序排列。
请求出操作完成后的序列。
输入描述
输入的第一行包含两个整数 n,mn,m,分别表示序列的长度和操作次数。
接下来 mm 行描述对序列的操作,其中第 i 行包含两个整数 pi,qipi,qi 表示操作类型和参数。当 pi=0pi=0 时,表示将 a1,a2,⋅⋅⋅,aqia1,a2,⋅⋅⋅,aqi 降序排列;当 pi=1pi=1 时,表示将 aqi,aqi+1,⋯ ,anaqi,aqi+1,⋯,an 升序排列。
输出描述
输出一行,包含 nn 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。
输入输出样例
示例
输入
3 3
0 3
1 2
0 2
输出
3 1 2
样例说明
原数列为 (1,2,3)(1,2,3)。
第 11 步后为 (3,2,1)(3,2,1)。
第 22 步后为 (3,1,2)(3,1,2)。
第 33 步后为 (3,1,2)(3,1,2)。与第 22 步操作后相同,因为前两个数已经是降序了。
评测用例规模与约定
对于 30%30% 的评测用例,n,m≤1000n,m≤1000;
对于 60%60% 的评测用例,n,m≤5000n,m≤5000;
对于所有评测用例,1≤n,m≤100000,0≤pi≤1,1≤qi≤n1≤n,m≤100000,0≤pi≤1,1≤qi≤n。
运行限制
- 最大运行时间:2s
- 最大运行内存: 256M
题解:(暴力,十个样例只对三个,其他会超时)
#include <stdio.h>
void descendingSort(int arr[], int start, int end) {
int i, j, temp;
for (i = start; i < end; i++) {
for (j = i+1; j <= end; j++) {
if (arr[i] < arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
void ascendingSort(int arr[], int start, int end) {
int i, j, temp;
for (i = start; i < end; i++) {
for (j = i+1; j <=end; j++) {
if (arr[i] > arr[j]) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
int arr[n];
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
for (int i = 0; i < m; i++) {
int p, q;
scanf("%d %d", &p, &q);
if (p == 0) {
descendingSort(arr, 0, q - 1);
} else {
ascendingSort(arr, q - 1, n - 1);
}
}
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
8.题目:路径
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
题解:
#include <stdio.h>//求1到达2021的最短路径
#include <stdlib.h>
int gcd(int a,int b)//最大公约数 辗转相除法
{
if(a%b==0) return b;
else return gcd(b,a%b);
}
int gbs(int a,int b)//最小公倍数=a*b/最大公约数
{
return a*b/gcd(a,b);
}
int min(int a,int b)
{
return a<b?a:b;
}
int main(int argc, char *argv[]){
int i=1,j,f[2022]={0};//f[n]表示1到n的最短路径长
/*先求1能直接到达的点(2..22)更新f数组内的数据,
把已经求出最短路径的点归到一类(i),再求这类点能直接到达的点(j)最短路径,
多个不同点能到达同一个点,可以通过循环求出f[n]的最佳结果*/
for(i=1;i<=2021;i++){
for(j=i+1;j<=i+21&&j<=2021;j++){
if(f[j]==0) f[j]=f[i]+gbs(i,j);
else f[j]=min(f[j],f[i]+gbs(i,j));
}
}
//比较最短路径是比较1到点j的路径长,而不是i到j的路径长!!
printf("%d",f[2021]);
return 0;
}
9.题目:货物摆放
题目描述
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n=L×W×H。
给定 nn,请问有多少种堆放货物的方案满足要求。
例如,当 n=4 时,有以下 66 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。
请问,当 n=2021041820210418 (注意有 16 位数字)时,总共有多少种方案?
提示:建议使用计算机编程解决问题。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
题解:
#include <stdio.h>
long long n = 2021041820210418;
long long arr[1000000];
int main()
{
int ans = 0;
int coust = 0;
long long i = 0;
long long a, b, c;
//求出所有约数
for (i = 1; i * i <= n; i++)
{
if (n % i == 0)
{
arr[coust] = i;
coust++;
if (n / i != i)
{
arr[coust] = (n / i);
coust++;
}
}
}
for (a =0; a < coust; a++)
for (b = 0; b < coust; b++)
for (c = 0; c < coust; c++)
{
if (arr[a]*arr[b]*arr[c] == n)
{
ans++;
}
}
printf("%d",ans);
return 0;
}
10.题目:卡片
问题描述
小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一 位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有 两位同学的卡片都是一样的。
给定 n, 请问小蓝的卡片至少有多少种?
输入格式
输入一行包含一个正整数表示 n 。
输出格式
输出一行包含一个整数, 表示答案。
样例输入
6
样例输出
3
样例说明
小朋友们手中的卡片可能是: (1,1),(1,2),(1,3),(2,2),(2,3),(3,3)。
评测用例规模与约定
对于 50 的评测用例, 1≤n≤104 。
对于所有评测用例, 1≤n≤109。
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
题解:
1.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
long int n,sum;
scanf("%ld",&n);
for(int i=1;;i++)
{
sum=i+(i*(i-1))/2;
if(sum>=n)
{
printf("%d",i);
break;
}
}
return 0;
}
2.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n; cin >> n;
int ans = 0;
for (int i = 1, cnt = 0; i <= n; ++i)
{
if (cnt >= n) break;
ans++;
cnt += i;
}
cout << ans << endl;
return 0;
}