小埋摸鱼学习法 - 算法竞赛
type: channel
link: https://www.topzhang.cn/category/QA/
description: 一些竞赛题的总结
items: 算法小抄
items: 数组排序常见方式
items: 斐波那契的几种实现方式
items: 快速排序
items: 进栈出栈问题
items: 采药问题（动态规划）
items: 最大公约数求法
items: 螺旋折线
items: 大数相乘
items: 明码

算法小抄
type: item
date: 2023-03-04T12:26:00+00:00
description: 算法小抄查找表问题两个数组的交集 II-350给你两个整数数组 nums1 和 nums2 ，请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数，应与元素在两个数组中都出现的次数一致（如果出现次数不一致，则考虑取较小值）。可以不考虑输出结果的顺序。示例 1：输入：nums1 = [1,2,2,1], nums2 = [2,2] 输出：[2,2]示例 2:输入：nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出：[4,9]提示：1 <= nums1.length, nums2.length <= 1000 0 <= nums1[i], nums2[i] <= 1000题解：分别建立两个map 存储两个数组中每个数的出现次数，以数为key，该数出现的次数为value，然后对其中一个map进行遍历，如果这个数在两个map都存在那就取出这个数在两个map中出现的最小次数，最后在push相应的次数到结果数组中即可。function intersect(nums1: number[], nums2: number[]): number[] { // 交集查询 const map1 = makeCountMap(nums1); const map2 = makeCountMap(nums2); const res:number[] = []; for (const key of map1.keys()) { const count1 = map1.get(key) as number; const count2 = map2.get(key); if(count2) { const count = Math.min(count1, count2); for(let i = 0; i < count; i++) { res.push(key); } } } return res; }; function makeCountMap(arr:number[]):Map<number,number> { const map = new Map(); for (const item of arr) { if(map.has(item)) { // 存储每个数出现的次数 map.set(item,map.get(item)+1) } else { map.set(item,1) } } return map; }双指针问题最接近的三数之和-16给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数，使它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在恰好一个解。示例 1：输入：nums = [-1,2,1,-4], target = 1 输出：2 解释：与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。示例 2：输入：nums = [0,0,0], target = 1 输出：0提示：3 <= nums.length <= 1000 -1000 <= nums[i] <= 1000 -104 <= target <= 104题解：首先对数组进行升序排序，然后建立两个指针，left和right left从基准点(从第一个数开始)的下一个数开始，right从最后开始，然后left逐渐向right靠拢，每次移动就将三数的和和目标和的差存储起来，每次都存储最小的差值。如果和大于目标值，说明right的值偏大，就需要将right左移，如果和小于目标值就需要将left右移。function threeSumClosest(nums: number[], target: number): number { let min = Infinity; let res; if(nums.length === 3) { return nums[0]+nums[1]+nums[2] } // 首先升序排序 nums = nums.sort((a, b) => a - b); // 取基准点 for(let i = 0; i <= nums.length - 3; i++) { let base = nums[i]; let left = i+1 let right = nums.length-1; while(left < right){ let sum = base + nums[left] + nums[right]; let diff = Math.abs(target-sum); if(diff < min) { // 记录当前最小值 min = diff; // 记录最接近的和 res = sum; } if(sum < target) {…

数组排序常见方式
type: item
date: 2021-09-05T14:06:00+00:00
description: 数组排序常见方式冒泡排序基本思路：将数组的每一项与后一项进行比较，如果前一项大于后一项就交换两者位置。//冒泡排序 Array.prototype.bubleSort = function () { for (let i = this.length - 1; i >= 0; i--) { for (let j = 0; j < i; j++) { if (this[j] > this[j + 1]) { //交换函数 swap.call(this, j, j + 1); } } } };优化版:Array.prototype.bubleSort = function () { for (let i = this.length - 1; i >= 0; i--) { let b = false; for (let j = 0; j < i; j++) { if (this[j] > this[j + 1]) { //交换函数 b = true; swap.call(this, j, j + 1); } } if(!b) return;//表示已经是有序的了，不用再交换 } };选择排序基本思路：从头开始，设置第一个数为最小数，保存其索引，将该数与后面的数进行比较，找到比该数更小的数就更新保存的索引，第一遍遍历完后，就交换第一个数与保存的索引数的位置。第二次从第二个数开始。遍历后交换第二数与最小数的索引对应数的位置。Array.prototype.selectionSort = function () { let min = 0; for (let i = 0; i < this.length - 1; i++) { //初始最小数索引 min = i; for (let j = i + 1; j < this.length; j++) { if (this[min] > this[j]) { //更新最小数索引 min = j; } } //遍历完后就交换索引 swap.call(this, i, min); } };插入排序基本思路：首先将第一个元素看作有序，取出其后面一位的元素保存，将保存的元素与前面的有序元素比较，如果小于前面的有序元素就将前面的元素后移，如果移动后前面没有元素或者遇到了比自己小的元素就记录当前索引，并将保存的元素插入到这里，依次类推。Array.prototype.insertSort = function () { let temp, j; for (let i = 1; i < this.length; i++) { //记录要将temp插入的位置 temp = this[i]; j = i; while (this[j - 1] > temp && j > 0) { this[j] = this[j - 1]; j--; } this[j] = temp; } };图例：第一次：将4与前面的6比较，小于将6向后移动，然后到头后将保存的4插入到第一个位置。第二次：保存了2这个数，将这个数与前面的4，6这两个有序数进行比较，都小，就向后移动，到头后将2插入到第一个位置。以此类推遍历。希尔排序思路与插入排序一样，可以把普通的插入排序看作间隔为1的希尔排序，希尔排序是每次遍历都会以不同的间隔进行插入排序，比如这里按照数组的1/2，1/4等来进行分组排序。Array.prototype.hillSort = function () { let temp, j; const length = this.length; //增量 let gap = Math.floor(length / 2); while (gap >= 1) { for (let i = gap; i < length; i += gap) { temp = this[i]; j = i; while (this[j - gap] > temp && j > gap - 1) { this[j] = this[j - gap]; j -= gap; } this[j] = temp; } gap = Math.floor(gap / 2); } };快速排序基本思路：首先找到一个枢纽，一般该枢纽获取方式是取数组的第一个，中间，最后一个数，取这三个数的中位数。Array.prototype.quickSort = function (left, right) { //结束条件 if (left >= right) return; //获取枢纽 let pivot = this.media(left, right); let i = left; let j = right - 1; //交换操作 while (i < j) { while (th…

斐波那契的几种实现方式
type: item
date: 2021-07-09T11:53:54+00:00
description: 斐波那契的几种实现方式斐波那契数组为 0 1 1 2 3 5 8....1.普通递归方式function fib(n) { if(n <= 1) return n; return fib(n - 2) + fib(n - 1); } //测试耗时（仅供参考） testTime(() => { console.log(fib(30)); }) function testTime(cb) { let begin = Date.now(); cb(); let after = Date.now(); console.log("消耗时间: "+ (after - begin) +" ms"); }输出结果：832040 消耗时间: 15 ms2. 递归优化版普通的递归方式在遇到n稍大的时候，会很久不出结果，比如n=64的时候基本算不出来对于普通的递归我们分析其时间复杂度就可以发现，其中出现了很多的重复计算，比如计算n=6，步骤如下图：计算fib6的时候需要计算fib5和fib4，而fib5需要fib4和fib3，这里fib4就重复计算了，而且我们可以通过上述的步骤发现该算法的时间复杂度约为2^n， 效率极其不佳。优化思路，利用一个数组记录我们算过的fib结果，当需要使用的时候直接用，就不需要在重新计算了let array = []; function fib1(n) { if(n <= 1) return n; if(array[n] !== undefined) { return array[n]; } array[n] = fib1(n - 2) + fib1(n - 1); return array[n]; }运算结果：832040 消耗时间: 4 ms3. 非递归方式function fib3(n){ if(n <= 1) return n; let fir = 0; let sec = 1; for(let i = 0; i < n - 1; i++) { sec += fir; fir = sec - fir; } return sec; }运算结果：832040 消耗时间: 5 ms这里的时间复杂度就为O（n）了4. 通项公式斐波拉契通项公式如下：代码如下：function fib4(n){ let c = Math.sqrt(5); return parseInt((Math.pow((1 + c) / 2, n) - Math.pow((1 - c) / 2, n)) / c); }运算结果：832040 消耗时间: 4 ms总结我们的算法优化基本是用尽量少的存储空间和尽量少的执行时间，需要根据数据量来选择最合适的算法，没有绝对的算法，我们根据情况可以时间换空间，空间换时间。常见的复杂度：

快速排序
type: item
date: 2020-01-11T11:46:00+00:00
description: 今天看了一个大佬写的，终于弄明白点了思路： 1．先从数列中取出一个数作为基准数。 2．分区过程，将比这个数大的数全放到它的右边，小于或等于它的数全放到它的左边。 3．再对左右区间重复第二步，直到各区间只有一个数（这个就是递归过程了）。 当然看这个思路还是有点不懂，下面就举一个例子来展示下过程： 如下是一个数组初始时，i = 0; j = 9; X = a[i] = 72由于已经将 a[0] 中的数保存到 X 中，可以理解成在数组 a[0] 上挖了个坑，可以将其它数据填充到这来。从j开始向前找一个比X小或等于X的数。当j=8，符合条件，将a[8]挖出再填到上一个坑a[0]中。a[0]=a[8]; i++; 这样一个坑a[0]就被搞定了，但又形成了一个新坑a[8]，这怎么办了？简单，再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数，当i=3，符合条件，将a[3]挖出再填到上一个坑中a[8]=a[3]; j--;然后数组变成下面：i = 3; j = 7; X=72再重复上面的步骤，先从后向前找，再从前向后找。从j开始向前找，当j=5，符合条件，将a[5]挖出填到上一个坑中，a[3] = a[5]; i++;从i开始向后找，当i=5时，由于i==j退出。此时，i = j = 5，而a[5]刚好又是上次挖的坑，因此将X填入a[5]。数组变为：可以看出a[5]前面的数字都小于它，a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。 最后可以看出： 该方法可以看成将基准数放回它原本位置的方法总结方法： 1．i =L; j = R; 将基准数挖出形成第一个坑a[i]。 2．j--由后向前找比它小的数，找到后挖出此数填前一个坑a[i]中。 3．i++由前向后找比它大的数，找到后也挖出此数填到前一个坑a[j]中。 4．再重复执行2，3二步，直到i==j，将基准数填入a[i]中。然后a[i]就是基准书原来的位置代码： void quick_sort(int s[], int l, int r) { if (l < r) { int i = l, j = r, x = s[l]; while (i < j) { while(i < j && s[j] >= x) // 从右向左找第一个小于x的数，直到找到了就跳出循环 j--; if(i < j) s[i] = s[j];//将这个小于x的数拿到左边去 i++； while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 i++; if(i < j) s[j] = s[i];//将这个大于x的数拿到右边去 j--； } s[i] = x; quick_sort(s, l, i - 1); // 递归调用 quick_sort(s, i + 1, r); }

进栈出栈问题
type: item
date: 2020-01-09T03:26:00+00:00
description: 问题描述：1~N范围内的所有自然数按照从小到大的顺序（1，2，...，N）依次等待进栈。比如现在N=3:我们知道有些出栈顺序是合法的，例如{3,2,1}/{1,2,3}等而有些出栈顺序是不可能出现（非法）的，例如{3,1,2}现在给出1组出栈顺序，请你判断其是否合法。输入：第1行包含1个整数N（1 <= N <= 20），代表元素个数。 第2行包含N的整数，代表出栈顺序，空格隔开。输出：如果非法，输出“No”； 如果合法，输出“Yes”，以及在整个入栈/出栈过程中，栈的最大size，空格隔开。 样例输入：样例1：4 2 4 3 1 样例2：4 2 4 1 3样例输出： 样例1：Yes 3 *合法，过程中{1,3,4}同时在栈中时size达到最大 样例2：No思路：该题就是考察近栈出栈的理解，该题我们可以用一个洗碗模型来解释：姐姐洗碗，妹妹把姐姐洗过的碗一个一个地放进碗橱摞成一摞。一共有n个不同的碗，洗前也是摞成一摞的，也许因为小妹贪玩而使碗拿进碗橱不及时，姐姐则把洗过的碗摞在旁边，问：小妹摞起的碗有多少种可能的方式？而问题的答案就是卡特兰数：f(n) = f(0)f(n-1) + f(1)f(n-2) + ... + f(n-1)*f(0)其通项：C(2n,n)/(n+1)但是这个问题考察的n个递增元素依次入栈，所以问题就相对简化了一些。虽然是以次进栈，但是在中途有元素也可以先出栈，所以该题就是要知道不一定所有的元素进栈完后才出栈。所以，我们根据规律得出，对于任何一个元素来说，当它进栈的时候，它下面的元素必然都比它小。因为我们前面所有元素都是按照从小到大的顺序进栈的。因为我们前面所有元素都是按照从小到大的顺序进栈的。而出栈的时候呢，当这个大的元素出栈的时候，后面接着要出栈的元素里只要是原来它下面的元素，就必然一个比一个小。所以，我们也可以概括成这样，对于栈里任何一个出栈的元素来说，生成的序列里它后面所有比它小的元素必然构成一个递减的序列。 所以，按照这个规律，我们可以来判断一个给定的序列是否为通过入栈出栈生成的。代码如下： #include<bits/stdc++.h> using namespace std; bool isRight(vector<int> a) { //int marked[a.size()]; for(int i=0;i<a.size();i++) { //if(marked[i]) continue; int item=a[i]; //marked[i]=true; for(int j=i+1;j<a.size();j++) { //if(marked[j]) continue; if(a[j]<a[i])//找到比它小的元素，而这些比它小的元素要构成递减 { if(a[j]>item) return false; else { item=a[j];//用于和下一个a[j]作比较，来判断是否为递减 } //marked[j]=true; } } } return true; } int main() { int n,x,k=1; vector<int> a; list<int> size; cin>>n; for(int i=0;i<n;i++) { cin>>x; a.push_back(x); } if(isRight(a)) { cout<<"Yes"; for(int i=0;i<a.size();i++)//用于判断进栈个数最大时的size { k=1; for(int j=i+1;j<a.size();j++) //就是判断每个数所在的递减数列的最大size { if(a[j]<a[i]) { k++; } size.push_back(k); } } size.sort(); cout<<" "<<size.back(); //输出最大的size } else cout<<"No"; return 0; }

采药问题（动态规划）
type: item
date: 2020-01-08T12:18:00+00:00
description: 题目如下：辰辰是个很有潜能、天资聪颖的孩子，他的梦想是称为世界上最伟大的医师。为此，他想拜附近最有威望的医师为师。医师为了判断他的资质，给他出了一个难题。医师把他带到个到处都是草药的山洞里对他说：“孩子，这个山洞里有一些不同的草药，采每一株都需要一些时间，每一株也有它自身的价值。我会给你一段时间，在这段时间里，你可以采到一些草药。如果你是一个聪明的孩子，你应该可以让采到的草药的总价值最大。”如果你是辰辰，你能完成这个任务吗？ 输入：输入的第一行有两个整数T（1 <= T <= 1000）和M（1 <= M <= 100），T代表总共能够用来采药的时间，M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间（包括1和100）的的整数，分别表示采摘某株草药的时间和这株草药的价值。 输出：输出只包括一行，这一行只包含一个整数，表示在规定的时间内，可以采到的草药的最大总价值。样例输入： 70 3 71 100 69 1 1 2样例输出： 3思路： 1.首先以采摘的时间为阶段。 2.确立状态及状态变量：j时间内采摘M种药品获得的最大价值。 3.决策：如果采摘第i种药品获得的价值大于不采摘的情况，最大价值等于采摘第i种药品获得的价值；反之，最大价值等于不采 摘第i种药品获得的价值。 4.状态转移方程：F[j] = max(F[j], F[j - t[i]] + v[i]);//这个是求出当剩余时间为多少时，可采得的草药价值的最大值 代码如下： #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1005; int t[MAXN];//每株药的采摘所需时间 int v[MAXN];//每株药的价值 int F[MAXN];//所给时间能采到药草的最大值，例如F[70]表示在时间70内能采到的药草最大价值 int main() { //初始化每个数组，赋值为0 memset(v, 0, sizeof(v)); memset(t, 0, sizeof(t));//每株药需要的时间 memset(F, 0, sizeof(F));//采药的总价值 int m, T, M; cin >> T >> M; for (int i = 1; i <= M; i++) { cin >> t[i] >> v[i]; } for (int i = 1; i <= M; i++) { for (int j = T; j >= 1; j--)//j表示剩余时间 { if (j >= t[i]) { F[j] = max(F[j], F[j - t[i]] + v[i]);//这个是求出当剩余时间为多少时，可采得的草药价值的最大值 } } } cout << F[T]; return 0; }

最大公约数求法
type: item
date: 2020-01-07T09:06:00+00:00
description: 下面列出了三种方式求两数的最大公约数，另外还有一个公式：ab=最大公约数最小公倍数1.辗转相除法 int max_gys(int a, int b) { int c = b;//保证两数相同是可直接输出结果 while(a%b!=0) { c = a%b; a = b; b = c; } return c; }2.辗转相减法 int max_gys(int a,int b) { while(a != b)//当减到两数相等时任意一个数就是原两者的最大公约数 { if(a>b) { a = a - b; } else { b = b - a; } } return b; }3.枚举法（穷举法） int max_gys(int a,int b) { int item=a;//这里是两个数任意一个，公约数大小不会超过两个数任意一个的 while(1) { if(a%item==0&&b%item==0) break; item--; } return item; }

螺旋折线
type: item
date: 2020-01-06T04:45:00+00:00
description: 题目如下： 如图所示的螺旋折线经过平面上所有整点恰好一次。 对于整点(X, Y)，我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度。例如dis(0, 1)=3, dis(-2, -1)=9 给出整点坐标(X, Y)，你能计算出dis(X, Y)吗？【输入格式】X和Y对于40%的数据，-1000 <= X, Y <= 1000 对于70%的数据，-100000 <= X， Y <= 100000 对于100%的数据, -1000000000 <= X, Y <= 1000000000 【输出格式】输出dis(X, Y) 输入.in输出.out样例输入0 1样例输出3 解题思路： 这里我用的暴力计算，通过观察发现规律，首先我把它分为四个象限每个象限有个中心点满足x=y（第三象限除外，第三象限我定义的是满足x-y=-1） 然后我们就可以围绕这个中心点来计算了，我们通过观察发现： 第一象限的中心点（x，y），到原点的折线距离是： 1*2x 例如点（3.3） 2*（2x-1） 1*6 2*（2x-2） 2*5 ... 2*4 2*1 2*3 ... 2*1第二象限的中心点（x,y）,到原点折线的距离是： 2*（2x-1） 2*（2x-2） 2*（2x-3） ... 2*1 第三象限的中心点（x,y）,到原点折线的距离是（这里注意第三象限的中心点是满足x-y=-1）： 1*（2x-1） 2*（2x-2） 2*（2x-3） ... 2*1第四象限的中心点（x,y）,到原点折线的距离是： 2*2x 2*（2x-1） 2*（2x-2） 2*（2x-3） ... 2*1 推出这个规律后我们就可以把对应象限的点先用其所在象限的中心点代替计算然后在计算点与中心点的距离 最后就可计算出实际的折现距离了代码如下： #include <iostream> using namespace std; int main() { int x,y,k; int cha,sum=0; cin>>x>>y; //1象限 if(x>=0&&y>=0)//判断象限 { if(x>y)//判断点在中心点的上方还是下方，用于计算实际点与中心点的差值 { cha=x-y; y=x; } else { cha=x-y; x=y; } sum=2*x; k=2*x; for(int i=1;i<k;i++)//通过推出的规律累加求得中心点到原点折线距离 { sum+=2*i; } sum+=cha;//与求得的差值计算就求出实际点到原点折现的距离 cout<<sum; } //2象限 if(x<0&&y>=0) { if(y/x<-1) { cha=x+y; x=-y; } else { cha=x+y; y=-x; } k=2*y; for(int i=1;i<k;i++) { sum+=2*i; } sum+=cha; cout<<sum; } //3象限 if(x<0&&y<0) { if(x<y) { cha=y-x-1; y=x+1; } else { cha=y-x-1; x=y-1; } sum=-2*x-1; k=-2*x-1; for(int i=1;i<k;i++) { sum+=2*i; } sum+=cha; cout<<sum; } //4象限 if(x>=0&&y<0) { if(y/x>-1) { cha=-x-y; y=-x; } else { cha=-x-y; x=-y; } k=2*x; for(int i=1;i<=k;i++) { sum+=2*i; } sum+=cha; cout<<sum; } }

大数相乘
type: item
date: 2020-01-05T09:33:00+00:00
description: 题目如下：描述： 求两个不超过200位的非负整数的积。输入： 有两行，每行是一个不超过200位的非负整数，没有多余的前导0。输出： 一行，即相乘后的结果。结果里不能有多余的前导0，即如果结果是342，那么就不能输出为0342。样例输入： 12345678900 98765432100样例输出： 1219326311126352690000思路： 这个题主要是考虑如果数据大于电脑所能储存的范围该如何计算，这就可以回归我们如何手算两数相乘了 可以将数据先以字符串的形式储存到数组中，然后再转换为整型进行计算。 当然我们的核心思路就是如下： 乘法原理： 乘法竖式 1 2 3 * 4 5 —————————————— 6 1 5 + 4 9 2 —————————————— 5 5 3 5 1.核心代码（乘法运算部分）是由模拟乘法竖式算出来的，我们要知道：(1) 数1的倒数第i位与数2的倒数第j位相乘所得到的值应存在结果的倒数第i+j位上。 (2) 如果结果的i+j位大于9，则进位到i+j+1位。 num[i+j]+=big1[i]*big2[j]; num[i+j+1]+=num[i+j]/10; num[i+j]%=10;要注意考虑乘积为零的时候 for(i=m+n-1;i>=1;i--)//除去末尾后的零，这里i>=1就是考虑了乘积为0 { if(num[i]==0)//遇到0就删除，最多删到只剩一个0，就是结果为0的时候 k--; else break; }要知道一个i位和一个j位的数相乘，得到的结果不会超过i+j位源码如下： #include <iostream> #include<bits/stdc++.h> using namespace std; int main() { char a[200]; char b[200]; int big1[200]={0}; int big2[200]={0}; int num[2000]={0}; int m,n; int i,j,k; cin>>a; m=strlen(a);//获得输入字符串的长度 cin>>b; n=strlen(b); for(i=0;i<m;i++)//将字符转换为数再倒序输入 { big1[m-1-i]=a[i]-'0'; } for(i=0;i<n;i++) { big2[n-1-i]=b[i]-'0'; } for(i=0;i<m;i++) { for(j=0;j<n;j++) { num[i+j]+=big1[i]*big2[j]; num[i+j+1]+=num[i+j]/10; num[i+j]%=10; } } k=m+n;//结果长度 for(i=m+n-1;i>=1;i--)//除去末尾后的零 { if(num[i]==0) k--; else break; } for(i=k-1;i>=0;i--)//倒序输出 { cout<<num[i]; } }

明码
type: item
date: 2019-12-31T08:34:00+00:00
description: 题目如下 汉字的字形存在于字库中，即便在今天，16点阵的字库也仍然使用广泛。16点阵的字库把每个汉字看成是16x16个像素信息。并把这些信息记录在字节中。一个字节可以存储8位信息，用32个字节就可以存一个汉字的字形了。把每个字节转为2进制表示，1表示墨迹，0表示底色。每行2个字节，一共16行，布局是：第1字节，第2字节 第3字节，第4字节 .... 第31字节, 第32字节 这道题目是给你一段多个汉字组成的信息，每个汉字用32个字节表示，这里给出了字节作为有符号整数的值。题目的要求隐藏在这些信息中。你的任务是复原这些汉字的字形，从中看出题目的要求，并根据要求填写答案提示这段信息是（一共10个汉字）：4 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 016 64 16 64 34 68 127 126 66 -124 67 4 66 4 66 -124 126 100 66 36 66 4 66 4 66 4 126 4 66 40 0 164 0 4 0 4 0 4 32 -1 -16 4 32 4 32 4 32 4 32 4 32 8 32 8 32 16 34 16 34 32 30 -64 00 -128 64 -128 48 -128 17 8 1 -4 2 8 8 80 16 64 32 64 -32 64 32 -96 32 -96 33 16 34 8 36 14 40 44 0 3 0 1 0 0 4 -1 -2 4 0 4 16 7 -8 4 16 4 16 4 16 8 16 8 16 16 16 32 -96 64 6416 64 20 72 62 -4 73 32 5 16 1 0 63 -8 1 0 -1 -2 0 64 0 80 63 -8 8 64 4 64 1 64 0 -1280 16 63 -8 1 0 1 0 1 0 1 4 -1 -2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 5 0 2 02 0 2 0 7 -16 8 32 24 64 37 -128 2 -128 12 -128 113 -4 2 8 12 16 18 32 33 -64 1 0 14 0 112 01 0 1 0 1 0 9 32 9 16 17 12 17 4 33 16 65 16 1 32 1 64 0 -128 1 0 2 0 12 0 112 00 0 0 0 7 -16 24 24 48 12 56 12 0 56 0 -32 0 -64 0 -128 0 0 0 0 1 -128 3 -64 1 -128 0 0注意：需要提交的是一个整数，不要填写任何多余内容。这个题我拿到也是看来很久查资料才弄懂是啥意思，题目就是把这些数字转为二进制码，每个十进制数用一个八位的二进制码来储存，然后再输出，但是这里的输出要求是每个八进制中1代表字的组成部分（可随便用一个符号来输出，用于与底色区分），0代表底色，而且一行只输出两个八位二进制数处理后的输出结果，然后再换行。最后根据输出的信息来解题。所以搞懂题后，就觉得这个题很简单了。代码如下： #include <iostream> #include<bits/stdc++.h> using namespace std; int main() { int bin[8]={0};//八位的二进制码 int number; int item=0; while(cin>>number) { if(number<0) //如果是负数就转化为补码来计算其二进制 number=number+256; for(int i=7;i>=0;i--) { bin[i]=number%2; number=number/2; } for(int j=0;j<8;j++) { if(bin[j]==1) { cout<<"@"; } else { cout<<" "; } } item++; //输出两个就换行 if(item%2==0) { cout<<endl; } } }这样就得知该题让计算的就是九的九次方。 那么答案就为 387420489