重新排列 1234 使得每一个数字都不在原来的位置上,一共有( 9 )种排法。
方法一:只有四个数,可以采用手工枚举的方式。
1234 2143 2413 3142 3412 3421 4132 4312 4321
因此答案为 9。
方法二:这是错排类问题。nn 个不同元素的一个错排可由下述两个步骤完成:
第一步,“错排” 11 号元素(将 11 号元素排在第 22 至第 nn 个位置之一 ),有 n-1n−1 种方法。
第二步,“错排”其余n−1 个元素,按如下顺序进行。视第一步的结果,若 1 号元素落在第 kk 个位置,第二步就先把 k 号元素“错排”好,kk 号元素的不同排法将导致两类不同的情况发生:1、k 号元素排在第 1 个位置,留下的 n−2 个元素在与它们的编号集相等的位罝集上“错排”,有 f(n -2)种方法;2、k 号元素不排第 1 个位置,这时可将第 1 个位置“看成”第 k个位置(也就是说本来准备放到 kk 位置为元素,可以放到 1 位置中),于是形成(包括 kk 号元素在内的)n−1 个元素的“错排”,有 f( n- l) 种方法。据加法原理,完成第二步共有 f(n-2)+f(n-1) 种方法。根据乘法原理,nn 个不同元素的错排种数 f(n)= (n-l)[f(n-2)+f(n-l)](n > 2)。
假设有 n 封信,第一封信可放在 (2~n) 任一个信封里,共 n−1 种放法,设第一封信放在了第 k 个信封里,若此时第 k 封信放在了第 1 个信封里,则只要将剩下的 n-2 错排,即 f(n-2),若第 k 封信没有放在了第 1个信封里,可将第 1 封信的位置看成是“第 k 个位置”,即将 n−1 封信错排,即为 f(n-l)。由递推可得:
f(n)=(n-1)\times[f(n-1)+f(n-2)]f(n)=(n−1)×[f(n−1)+f(n−2)]
f(1)=0,f(2)=1,f(3)=2,f(4)=9f(1)=0,f(2)=1,f(3)=2,f(4)=9。
(打印月历)输入月份 m(1 \le m \le 12)m(1≤m≤12),按一定格式打印 20152015 第 mm 月的月历。
例如,2015 年一月的月历打印效果如下(第一列为周日):
#include<iostream>
using namespace std;
const int dayNum[]={-1,31,28,31,30,31,30,31,31,30,31,30,31};
int m, offset, i;
int main()
{
cin >> m;
cout <<"S M T W T F S"<<endl;//' '为tab制表符
①;
for (i = 1; i < m; i++)
offset = ②;
for (i = 0; i < offset; i++)
cout <<' ';
for (i = 1; i <= ③;i++)
{
cout << ④;
if(i==dayNum[m]||⑤==0)
cout << endl;
else
cout << ' ';
}
return 0;
}
填空位置 ①:
offset = 4
填空位置 ②:
(offset + dayNum[i]) % 7
填空位置 ③:
dayNum[m]
填空位置 ④:
i
填空位置 ⑤:
(offset + i) % 7
首先我们先看到较为简单的第三、四两空,这两空对应的过程显然就是输出日历了。for
循环内应该是对每一天输出一个日期,因此循环范围就应该是这个月的天数,也就是dayNum[m]
。什么时候应该输出换行符呢?要么就是所有日期输出完毕了(i==dayNum[m]
),要么就是输出了一个星期之后进行换行,所以这里对应的就是每个星期结束,也就是当i
为 77 的倍数时进行换行。下面再回过来看前两空。通过上面一个for
循环可以看出来这个offset
是用来控制月历开始的时候要输出多少的空位,再参照题目给出的第一个月的月历就可以知道offset
初值应该是 44,即第一空对应需要做的事情。但是这个offset
只是对于第一个月正确,因此需要再加上所有小于 11 月的月份的天数,计算offset
的方法即为(offset+dayNum[i]) % 7
。
(中位数)给定 nn(nn 为奇数且小于 10001000)个整数,整数的范围在00~mm(0 \lt m \lt 2^{31}0<m<231)之间,请使用二分法求这 nn 个整数的中位数。所谓中位数,是指将这 nn 个数排序之后,排在正中间的数。
#include <iostream>
using namespace std;
const int MAXN = 1000;
int n,i,lbound,rbound,mid,m,count;
int x[MAXN];
int main()
{
cin >> n >> m;
for(i = 0; i < n; i++)
cin >> x[i];
lbound = 0;rbound = m;
while(①) {
mid=(lbound+rbound)/2;
②;
for(i = 0; i < n; i++)
{
if(③)
④;
}
if(count > n/2)
lbound = mid + 1;
else
⑤;
}
cout << rbound << endl;
return 0;
}
填空位置 ①:
lbound < rbound
填空位置 ②:
count = 0
填空位置 ③:
x[i] > mid
填空位置 ④:
count++
填空位置 ⑤:
rbound = mid
这是一道经典的左闭右闭的二分题,整个题目的过程为:先二分答案,再遍历整个数组验证。第一空是二分的条件,所以应该为lbound<rbound
。第二空应该是将计数器count
初始化操作,第三空、第四空就对应着统计大于(或小于)mid
的数值个数的条件与过程,第五空则是调整右边界,可以参照左边界的调整方法仿写为rbound=mid
。
(01) 每个节点有零个或多个子节点;
(02) 没有父节点的节点称为根节点;
(03) 每一个非根节点有且只有一个父节点;
(04) 除了根节点外,每个子节点可以分为多个不相交的子树。