题目A: 空间(5分)题目B:卡片(5分)题目C:直线(10分)题目D:货物摆放(10分)题目E:路径(15分)题目F:时间显示(15分)题目G:砝码称重(20分)题目H:杨辉三角形题目I:双向排序(25分)题目J:括号序列
题目A: 空间(5分)
题目描述
小蓝准备用256MB 的内存空间开一个数组,数组的每个元素都是 32 位二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问256MB 的空间可以存储多少个32 位二进制整数?
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。67108864
题目分析
题目代码
#include题目B:卡片(5分)int main() { printf("%d", 256 >> 2 << 20); }
题目描述
小蓝有很多数字卡片,每张卡片上都是数字0到9。
小蓝准备用这些卡片来拼一些数,他想从1开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从1拼到多少。
例如,当小蓝有30张卡片,其中0到9各3张,则小蓝可以拼出1到10,但是拼11时卡片1已经只有一张了,不够拼出11。
现在小蓝手里有0到9的卡片各2021张,共20210张,请问小蓝可以从1拼到多少?3181
提示:建议使用计算机编程解决问题。
题目分析
题目代码(1)
#includeint n, ans, cnt; int main() { while (1) { n = ans; while (n) { if (n % 10 == 1) cnt++; n /= 10; } if (cnt < 2021) ans++; else break; } printf("%d", ans); }
题目代码(2)
#include #include题目C:直线(10分)#include using namespace std; int s[10]; bool check(int x) { while (x) { int t = x % 10; x = x / 10; if (--s[t] < 0) return false; } return true; } int main() { for (int i = 0; i < 10; i++) s[i] = 2021; for (int i = 1;; i++) { if (!check(i)) { //检查该数是否已经用完,不够用即最后一个数为所求的数 cout << i - 1 << endl; return 0; } } }
题目描述
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上, 那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z,即横坐标 是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数的点。这些点一共确定了 11 条不同的直线。
给定平面上 20 × 21个整点 (x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z,即横 坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之 间的整数的点。
请问这些点一共确定了多少条不同的直线。40257
题目分析
题目代码
//直线 //大致思路:依次枚举各个点,每两个点生成对应的斜率和截距。最后看有多少个不同的组合,即有多少条不同的直线 //注意事项:类型为double的两个数值a和b,即使数值相同,对应的double值也有可能不同,故在cpp中比较两个double值应判断其abs之差是否在很小的一个范围之内,例如1e-8 #include#include #include #include #include using namespace std; // 直线的最大数 const int N=200000; int n=0; struct Line { double k; double b; //结构体内嵌排序函数 bool operator < (const Line& t) const { // k不同的话,k小的在前 if(k!=t.k) return k 1e-8||fabs(l[i].b-l[i-1].b)>1e-8) res++; } cout< 题目D:货物摆放(10分)
题目描述
小蓝有一个超大的仓库,可以摆放很多货物。
现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。
小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 L、W、H 的货物,满足 n = L × W × H。
给定 n,请问有多少种堆放货物的方案满足要求。
例如,当 n = 4 时,有以下 6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 1。
请问,当 n = 2021041820210418 (注意有 16 位数字)时,总共有多少种方案?2430
提示:建议使用计算机编程解决问题。题目分析
先获得2021041820210418所有质因数,再通过质因数去组合从而获得所有的正约数,最后只需在所有的正约数找3个乘积为2021041820210418就行。题目代码
#include#include #include // 用vector来存储约数 #include using namespace std; // n比较大,会爆因子 typedef long long LL; int main() { LL n; cin>>n; // 枚举定义一下所有约数 vector d; //求n的所有约数个数,三层循环,枚举判断n=a*b*c for(LL i=1; i*i<=n; i++) { if(n%i==0) { d.push_back(i); if(n/i!=i) d.push_back(n/i); } } cout<< d.size()<< endl; int res = 0; //枚举一下a,b,c for(auto a:d) for(auto b:d) for(auto c:d) if(a*b*c==n) res++; cout< 题目E:路径(15分)
题目描述
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。10266837
提示:建议使用计算机编程解决问题。题目分析
题目代码
#include题目F:时间显示(15分)#include #include using namespace std; const int N=2200,M=N*50; int n; int h[N],e[M],w[M],ne[M],idx; int q[N],dist[N]; bool st[N]; int gcd(int a,int b)//欧几里得算法 辗转相除法(递归)求最大公约数 { return b ? gcd(b,a%b):a; } void add(int a,int b,int c)//添加一条边a->b,边权为c { e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } void spfa()//求1号点到n号点的最短距离 { int hh=0,tt=0; memset(dist, 0x3f,sizeof dist); dist[1]=0; q[tt ++]=1; st[1]=true; while(hh!=tt) { int t=q[hh ++]; if(hh==N) hh=0; st[t]=false; for(int i=h[t]; i!=-1; i=ne[i]) { int j=e[i]; if(dist[j]>dist[t]+w[i]) { dist[j]=dist[t]+w[i]; if(!st[j]) //如果队列已存在j,则不需要将j重复插入 { q[tt++]=j; if(tt==N) tt=0; st[j]=true; } } } } } int main() { n=2021; memset(h,-1,sizeof h); for(int i=1; i<=n; i++) { for(int j=max(1,i-21); j<=min(n,i+21); j++) { int d=gcd(i,j); // 最小公倍数 两个数乘机/最大公约数 i*j/d add(i,j,i*j/d); } } spfa(); printf("%dn",dist[n]); return 0; }
题目描述
小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00 : 00 : 00到当前时刻经过的毫秒数。
现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需显示出时分秒即可,毫秒也不用显示,直接舍去即可。
给定一个用整数表示的时间,请将这个时间对应的时分秒输出。
输入格式
输入一行包含一个整数,表示时间。
输出格式
输出时分秒表示的当前时间,格式形如 HH :MM:SS,其中HH 表示时,值为 0到 23,MM 表示分,值为 0 到 59,SS 表示秒,值为 0 到 59。时、分、秒不足两位时补前导0。
【测试用例】
Input:
46800999
Output:
13:00:00题目分析
题目代码
#include题目G:砝码称重(20分)#include #include using namespace std; typedef long long LL; int main() { LL n; cin >> n; //1s=1000ms,先去除毫秒 n /= 1000; // 每一天秒数=24*60*60=86400s,取出最后一天的秒数 n %= 86400; int h = n / 3600;//小时 //取出最后一天除了时以外的秒数 n %= 3600; int m = n / 60; //分钟 int s = n % 60; //秒 printf("%02d:%02d:%02dn", h, m, s); return 0; } 题目描述
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1, W2, · · · , WN。
请你计算一共可以称出多少种不同的重量?
注意砝码可以放在天平两边。
【输入】
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1, W2, W3, · · · , WN。
【输出】
输出一个整数代表答案。
【样例输入】
3
1 4 6
【样例输出】
10
提示
【样例说明】
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 4 (天平一边放 6,另一边放 4);
3 = 4 1;
4 = 4;
5 = 6 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 1;
10 = 4 + 6;
11 = 1 + 4 + 6。
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 15。
对于所有评测用例,1 ≤ N ≤ 100,N 个砝码总重不超过 100000。题目分析题目代码// dp:状态表示f(i,j)-->集合:只从前i个物品中选,且总重量为j的所有方案的集合;属性:是否为true // 状态计算:不选wi(f(i-1,j))、选+wi(f(i-1,j-wi))、选-wi(f(i-1,j+wi)) // f(n,1~n) #include题目H:杨辉三角形#include #include using namespace std; // -m<=j<=m const int N = 110, M = 200010, B = M / 2; int n, m; int w[N]; bool f[N][M]; int main() { scanf("%d", &n); // m代表所有砝码总重量 for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]), m += w[i]; f[0][B] = true; // j可能是负数,都要加一个偏移量(足够大的数) for (int i = 1; i <= n; i ++ ) for (int j = -m; j <= m; j ++ ) { f[i][j + B] = f[i - 1][j + B]; if (j - w[i] >= -m) f[i][j + B] |= f[i - 1][j - w[i] + B]; if (j + w[i] <= m) f[i][j + B] |= f[i - 1][j + w[i] + B]; } int res = 0; for (int j = 1; j <= m; j ++ ) if (f[n][j + B]) res ++ ; printf("%dn", res); return 0; } 题目描述
下面的图形是著名的杨辉三角形:
如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:
1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1,
给定一个正整数 N,请你输出数列中第一次出现 N是在第几个数?
输入格式
输入一个整数 N。
输出格式
输出一个整数代表答案。
Input:
6
Output:
13题目分析题目代码#include题目I:双向排序(25分)#include #include using namespace std; typedef long long LL; int n; LL C(int a, int b) { LL res = 1; for (int i = a, j = 1; j <= b; i --, j ++ ) { res = res * i / j; if (res > n) return res; } return res; } bool check(int k) { LL l = k * 2, r = max((LL)n, l); while (l < r) { LL mid = l + r >> 1; if (C(mid, k) >= n) r = mid; else l = mid + 1; } if (C(r, k) != n) return false; cout << r * (r + 1) / 2 + k + 1 << endl; return true; } int main() { cin >> n; for (int k = 16; ; k -- ) if (check(k)) break; return 0; } 题目描述
给定序列 (a1, a2, · · · , an) = (1, 2, · · · , n),即 ai = i。
小蓝将对这个序列进行 m 次操作,每次可能是将 a1, a2, · · · , aqi 降序排列,或者将 aqi , aqi+1, · · · , an 升序排列。
请求出操作完成后的序列。
【输入】
输入的第一行包含两个整数 n, m,分别表示序列的长度和操作次数。
接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 pi, qi 表示操作类型和参数。当 pi = 0 时,表示将 a1, a2, · · · , aqi 降序排列;当 pi = 1 时,表示将 aqi , aqi+1, · · · , an 升序排列。
【输出】
输出一行,包含 n 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。
【样例输入】
3 3
0 3
1 2
0 2
【样例输出】
3 1 2提示
【样例说明】
原数列为 (1, 2, 3)。
第 1 步后为 (3, 2, 1)。
第 2 步后为 (3, 1, 2)。
第 3 步后为 (3, 1, 2)。与第 2 步操作后相同,因为前两个数已经是降序了。
【评测用例规模与约定】
对于 30% 的评测用例,n, m ≤ 1000;
对于 60% 的评测用例,n, m ≤ 5000;
对于所有评测用例,1 ≤ n, m ≤ 100000,0 ≤ ai ≤ 1,1 ≤ bi ≤ n。题目分析题目代码#include题目J:括号序列#include #include #define x first #define y second using namespace std; typedef pair PII; const int N = 100010; int n, m; PII stk[N]; int ans[N]; int main() { scanf("%d%d", &n, &m); int top = 0; while (m -- ) { int p, q; scanf("%d%d", &p, &q); if (!p) { while (top && stk[top].x == 0) q = max(q, stk[top -- ].y); while (top >= 2 && stk[top - 1].y <= q) top -= 2; stk[ ++ top] = {0, q}; } else if (top) { while (top && stk[top].x == 1) q = min(q, stk[top -- ].y); while (top >= 2 && stk[top - 1].y >= q) top -= 2; stk[ ++ top] = {1, q}; } } int k = n, l = 1, r = n; for (int i = 1; i <= top; i ++ ) { if (stk[i].x == 0) while (r > stk[i].y && l <= r) ans[r -- ] = k -- ; else while (l < stk[i].y && l <= r) ans[l ++ ] = k -- ; if (l > r) break; } if (top % 2) while (l <= r) ans[l ++ ] = k -- ; else while (l <= r) ans[r -- ] = k -- ; for (int i = 1; i <= n; i ++ ) printf("%d ", ans[i]); return 0; }
题目描述
给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。
例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。
输入格式
输入一行包含一个字符串 s ss,表示给定的括号序列,序列中只有左括号和右括号。
输出格式
输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007(即 1 0 9 + 7 10^{9} + 7 109+7)的余数。
Input:
((()
Output:
5
评测用例规模与约定
对于 40% 的评测用例,∣ s ∣ ≤ 200。
对于所有评测用例,1 ≤ ∣ s ∣ ≤ 5000 。题目分析
题目代码
#include#include #include using namespace std; typedef long long LL; const int N = 5010, MOD = 1e9 + 7; int n; char str[N]; LL f[N][N]; LL work() { memset(f, 0, sizeof f); f[0][0] = 1; for (int i = 1; i <= n; i ++ ) if (str[i] == '(') { for (int j = 1; j <= n; j ++ ) f[i][j] = f[i - 1][j - 1]; } else { f[i][0] = (f[i - 1][0] + f[i - 1][1]) % MOD; for (int j = 1; j <= n; j ++ ) f[i][j] = (f[i - 1][j + 1] + f[i][j - 1]) % MOD; } for (int i = 0; i <= n; i ++ ) if (f[n][i]) return f[n][i]; return -1; } int main() { scanf("%s", str + 1); n = strlen(str + 1); LL l = work(); reverse(str + 1, str + n + 1); for (int i = 1; i <= n; i ++ ) if (str[i] == '(') str[i] = ')'; else str[i] = '('; LL r = work(); printf("%lldn", l * r % MOD); return 0; }



