18
)【解析】 n n n个相同的球放入 m m m个相同的盒子( n ≥ m n≥m n≥m),可以有空盒时的放法种数等于将 n n n分解为 m m m个、 ( m - 1 ) (m-1) (m-1)个、 ( m - 2 ) (m-2) (m-2)个、…、 2 2 2个、 1 1 1个数的和的所有种数之和。
8=8
8=1+7
,8=2+6
,8=3+5
,8=4+4
8=1+1+6
,8=1+2+5
,8=1+3+4
,8=2+2+4
,8=2+3+3
8=1+1+1+5
,8=1+1+2+4
,8=1+1+3+3
,8=1+2+2+3
,8=2+2+2+2
8=1+1+1+1+4
,8=1+1+1+2+3
,8=1+1+2+2+2
【解析】每周最多跑 21 21 21公里,所以优先安消耗卡路里最高的运动方案,即周五、六、日跑步一小时,一共可以跑 15 15 15公里,消耗
1800
千卡;剩余6公里安排在周一到周四跑两天即可,消耗600
千卡,一共消耗2400
千卡。
【解析】为了保证每种花色的牌最少,那么将 13 13 13张扑克分成 4 4 4份,每种花色各 3 3 3张,这样还剩 1 1 1张,根据鸽巢原理,必然有 1 1 1张扑克和其它 3 3 3张同花色,则至少(
4
)张牌的花色一致。
【解析】如果5位数的车牌倒过来恰好还是原来的数字,需要满足两个条件:
- 中间位的数字只能是 0 0 0、 1 1 1、 8 8 8
- 左边两位数字可以是 0 0 0、 1 1 1、 8 8 8 、 6 6 6、 9 9 9任意一个,确定了左边的数字,右边的数字选择旋转后对应的数字即可。
答案: C 3 1 × C 5 1 × C 5 1 = 75 C_3^1\times C_5^1 \times C_5^1=75 C31×C51×C51=75
DGJHEBIFCA
,中序遍历序列为 DBGEHJACIF
,则其前序遍历序列为( )。【解析】后序序列和中序序列可以惟一确定一棵二叉树。
该二叉树的前序序列为:
ABDEGHJCFI
#include
#include
using namespace std;
char st[100];
int main() {
scanf("%s", st);
int n = strlen(st);
for (int i = 1; i <= n; ++i) {
if (n % i == 0) {
char c = st[i - 1];
if (c >= 'a')
st[i - 1] = c - 'a' + 'A';
}
}
printf("%s", st);
return 0;
}
【解析】即求 1 1 1~ 18 18 18中
18
的约数个数。
任何一个大于 1 1 1的自然数 N N N,如果 N N N不为质数,那么 N N N可以唯一分解成有限个质数的乘积: N = P 1 a 1 × P 2 a 2 × P 3 a 3 × . . . × P n a n N = P_{1}^{a_1} × P_{2}^{a_2} × P_{3}^{a_3} × ... × P_{n}^{a_n} N=P1a1×P2a2×P3a3×...×Pnan,这里 P 1 < P 2 < P 3 < . . . < P n P_1 < P_2 < P_3 < ... < P_n P1<P2<P3<...<Pn均为质数,其中指数 a i a_i ai是正整数。这样的分解称为 N N N 的标准分解式。 那么 N N N 的约数个数 = ( a 1 + 1 ) × ( a 2 + 1 ) × ( a 3 + 1 ) × . . . × ( a n + 1 ) = (a_1 + 1) × (a_2 + 1) × (a_3 +1) × ... × (a_n + 1) =(a1+1)×(a2+1)×(a3+1)×...×(an+1)
18
标准分解式: 18 = 2 1 × 3 2 18=2^1\times3^2 18=21×32。
18
的约数个数 = ( 1 + 1 ) × ( 2 + 1 ) = 6 =(1+1)\times(2+1)=6 =(1+1)×(2+1)=6
【解析】 100000 100000 100000的标准分解式 = 2 5 × 5 5 =2^5\times5^5 =25×55。
100000
的约数个数 = ( 5 + 1 ) × ( 5 + 1 ) = 36 =(5+1)\times(5+1)=36 =(5+1)×(5+1)=36。
#include
using namespace std;
int n, m;
int a[100], b[100];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
a[i] = b[i] = 0;
for (int i = 1; i <= m; ++i) {
int x, y;
scanf("%d%d", &x, &y);
if (a[x] < y && b[y] < x) {
//第13行
if (a[x] > 0)
b[a[x]] = 0; //第15行
if (b[y] > 0)
a[b[y]] = 0;
a[x] = y;
b[y] = x;
}
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] == 0)
++ans;
if (b[i] == 0)
++ans; //第27行
}
printf("%d", ans);
return 0;
}
++ans
时,ans
一定是偶数。【解析】由于 x x x和 y y y都是在 [ 1 , n ] [1, n] [1,n] 范围内的整数,所以无论如何取值,
ans
最终都是偶数。但是题目中问的是执行完第 27 27 27 行的++ans
时的情况,27行在循环内部,当m= 1 , x= 1, y = 2
时,for
循环第一次执行到27行时,ans = 1
,为奇数。
a[i]
和 b[i]
不可能同时大于 0
。【解析】当
m= 1 , x= 1, y = 1
时,a[1]
和b[1]
都为1,同时大于0
。
【解析】当
m= 2
,第一次循环x= 1, y = 2
,此时a[1] = 2, b[2] = 1
;第二次循环x = 1, y = 3
时,a[1] < 3 && b[3] < 1
,a[1] > 0
,第15行被执行。
【解析】若 m m m 个 x x x 两两不同,且 m m m 个 y y y,其值可以是
x = 1, y = 1
,x = 2, y = 2
,…,x = m, y = m
,输入结束后a[1] = 1, b[1] = 1, a[2] = 2, b[2] = 2, ... , a[m] = m, b[m] = m
,数组a[]
和b[]
中各有m
个非零的数,此时ans = 2n - 2m
。
【解析】若 m m m 个 x x x 两两不同,且 m m m 个 y y y 都相等,其值可以是
x = 1, y = 1
,x = 2, y = 1
,…,x = m, y = 1
,输入结束后a[1] = 0, b[1] = m, a[2] = 0, b[2] = 0, ... , a[m] = 1, b[m] = 0
,除了a[m] = 1
和b[1] = m
,数组其它值都为0
,一共有2
个非零的数,此时ans = 2n - 2
。
#include
using namespace std;
const int maxn = 10000;
int n;
int a[maxn];
int b[maxn];
int f(int l, int r, int depth) {
if (l > r)
return 0;
int min = maxn, mink;
for (int i = l; i <= r; ++i) {
if (min > a[i]) {
min = a[i];
mink = i;
}
}
int lres = f(l, mink - 1, depth + 1);
int rres = f(mink + 1, r, depth + 1);
return lres + rres + depth * b[mink];
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i)
cin >> a[i];
for (int i = 0; i < n; ++i)
cin >> b[i];
cout << f(0, n - 1, 1) << endl;
return 0;
}
【解析】
f()
中返回lres + rres + depth * b[mink]
,如果b[]
全为0,结果一定为0。
【解析】最坏情况下,即递归树深度最大。例如数组
a[]
中元素是有序的,递归到下一层只减少一个元素,此时比较的次数为 100 + 99 + . . . + 1 = 5050 100 + 99 + ... + 1 = 5050 100+99+...+1=5050 。所以最坏情况下,比较运算执行的次数最接近的是6000
。
【解析】最好情况下,递归调用的深度应尽可能的小,每次二分时左右区间的长度相同。此时,递归树应是一棵完全二叉树,且高度为 ⌊ l o g 2 100 ⌋ + 1 = 7 \lfloor log_2^{100} \rfloor + 1 = 7 ⌊log2100⌋+1=7。
比较次数大约为 100 + 50 × 2 + 25 × 4 + 12 × 8 + 6 × 16 + 3 × 32 + 1 × 37 ≈ 100 + 50\times2 + 25\times4 + 12\times8+6\times16+3\times32+1\times37≈ 100+50×2+25×4+12×8+6×16+3×32+1×37≈600
b[i] = i + 1
,那么输出最大为( )。【解析】已知
b[0] = 1, b[1] = 2, ..., b[9] = 10
,要输出最大值,即depth * b[mink]
的和最大,那么depth
的值应该尽可能的大。与上道题类似,数组a[]
中元素是有序的,才能保证归深度最大,最大值 = 1 × 1 + 2 × 2 + 3 × 3 + . . . + 10 × 10 = 385 =1 \times\ 1+ 2 \times 2 + 3 \times 3 + ... + 10 \times 10=385 =1× 1+2×2+3×3+...+10×10=385。
b[i] = 1
,那么输出最小为( )。【解析】已知
b[i] = 1
,要输出最小值,即depth * b[mink]
的和最小,那么depth
的值应该尽可能的小,此时递归树应是一棵完全二叉树,且高度为 ⌊ l o g 2 100 ⌋ + 1 = 7 \lfloor log_2^{100} \rfloor + 1 = 7 ⌊log2100⌋+1=7。
如果是 7 7 7层的满二叉树总结点数应该是 2 7 − 1 = 127 2^7 - 1 =127 27−1=127,现在少了 27 27 27个,那么第 7 7 7层一共有 2 7 − 1 − 27 = 37 2^{7-1}-27=37 27−1−27=37个结点。
最终结果 = 37 × 7 + 32 × 6 + 16 × 5 + 8 × 4 + 4 × 3 + 2 × 2 + 1 × 1 = =37\times7+32\times6+16\times5+8\times4+4\times3+2\times2+1\times1= =37×7+32×6+16×5+8×4+4×3+2×2+1×1=580
<<
表示二进制左移运算符,例如 ( 11 ) 2 < < 2 = ( 1100 ) 2 (11)_{2}<<2=(1100)_2 (11)2<<2=(1100)2。^
表示二进制异或运算符,它将两个运算的数中的每个对应的二进制位一一进行比较,若两个二进制位相同,则运算结果的对应二进制位为 0
,反之为 1
。#include
using namespace std;
int n;
const int max_size = 1 << 10;
int res[max_size][max_size];
void recursive(int x, int y, int n, int t) {
if (n == 0) {
res[x][y] = ①;
return;
}
int step = 1 << (n - 1);
recursive(②, n - 1, t);
recursive(x, y + step, n - 1, t);
recursive(x + step, y, n - 1, t);
recursive(③, n - 1, !t);
}
int main() {
scanf("%d", &n);
recursive(0, 0, ④);
int size = ⑤;
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++)
printf("%d", res[i][j]);
puts("");
}
return 0;
}
【解析】分治思想,将以 ( x , y ) (x,y) (x,y)开头的矩阵变成4部分,分别进行递归处理。函数
recursive(int x, int y, int n, int t)
,x、y
表示矩阵的起点,n
表示要变换的次数,t
表示要填入的0、1
值。step
表示变换后矩阵对应元素距离。变换1次后,矩阵变为 2 × 2 2\times2 2×2,对应元素的的距离为1;变化2次后,矩阵变为 4 × 4 4\times4 4×4,对应元素的距离为2…。
空①,递归结束条件,当
n == 0
时,此时:res[x][y] = t
。
空②,递归处理左上角的矩阵,其左上角的坐标就是:x,y
空③,递归处理右下角的矩阵,其左上角的坐标为:x+step,y+step
空④,初始情况:n, 0
空⑤:经过n
次变换后,矩阵的大小为 2 n × 2 n 2^n\times2^n 2n×2n,size
为矩阵的行列个数,所以次空应为1<
。
ord[]
存储第二关键字排序的结果,数组 res[]
存储双关键字排序的结果。试补全程序。#include
#include
using namespace std;
const int maxn = 10000000;
const int maxs = 10000;
int n;
unsigned a[maxn], b[maxn],res[maxn], ord[maxn];
unsigned cnt[maxs + 1];
int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i)
scanf("%d%d", &a[i], &b[i]);
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; ++i)
①; // 利用 cnt 数组统计数量
for (int i = 0; i < maxs; ++i)
cnt[i + 1] += cnt[i];
for (int i = 0; i < n; ++i)
②; // 记录初步排序结果
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; ++i)
③; // 利用 cnt 数组统计数量
for (int i = 0; i < maxs; ++i)
cnt[i + 1] += cnt[i];
for (int i = n - 1; i >= 0; --i)
④ // 记录最终排序结果
for (int i = 0; i < n; i++)
printf("%d %d", ⑤);
return 0;
}
【解析】计数排序,通过统计每个待排序元素的出现次数,实现排序。本题中,
cnt[]
数组分别统计了两个关键字数组中每个元素的出现次数,同时又进一步处理了在区间 [ 0 , 10000 ) [0,10000) [0,10000)中,前i
个数中小于等于i
的关键字个数,可以计算每个关键字的排名。
数组ord[]
和数组res[]
都是以排名为下标,记录关键字在数组中的位置。数组ord[]
存储第二关键字排序的结果,ord[i] = j
表示排名为i
的第二个关键字在数组b[j]
中。数组res[]
存储双关键字排序的结果,res[i] = j
表示最终排名为i
的关键字在数组a[j]、b[j]
中。
空①,题目中提示先对第二个关键字排序,所以次空应填:
cnt[b[i]]++
,记录所有第二个关键字的出现次数。
空②,记录初步排序结果。通过上面代码cnt[i + 1] += cnt[i];
,cnt[i]
存储了小于等于i
的第二关键字的个数,那么cnt[b[i]]
即表示小于等于关键字b[i]
的关键字个数,即b[i]
的排名。题目中提示ord[]
存储第二关键字排序的结果,此处应将处理结果保存到数组ord[]
中,即ord[--cnt[b[i]]] = i
。--cnt[b[i]
保证了排名从0~n-1
,同时,b[i]
的出现次数减少一次。
空③,利用cnt
数组统计第一个关键字的数量,所以次空应填:cnt[a[i]]++
。
空④,通过上面代码cnt[i + 1] += cnt[i];
,cnt[i]
存储了小于等于i
的第一关键字的个数,cnt[a[i]]
即表示小于等于关键字a[i]
的关键字个数,即a[i]
的排名。cnt[a[ord[i]]]
表示排名为i
的第二关键字在数组位置ord[i]
,其对应的双关键字的排名为cnt[a[ord[i]]]
,它所在数组的位置为ord[i]
。所以此空应填:res[--cnt[a[ord[i]]]] = ord[i]
。
空⑤,数组res[]
存储双关键字排序的结果,所以次空应填:a[res[i]], b[res[i]]
。