全部知识点
(烽火传递) 烽火台又称烽燧,是重要的军事防御设施,一般建在险要处或交通要道上。 一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情。在 某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定的代价。为了使情报准确地传 递,在连续的 m个烽火台中至少要有一个发出信号。现输入 n、m和每个烽火台发出信号的代 价,请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传 递。
例如,有 5 个烽火台,他们发出信号的代价依次为 1,2,5,6,2,,且 m为 3,则总共最少 花费代价为 4,即由第 2 个和第 5 个烽火台发出信号。
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=100;
int n,m,r,value[SIZE],heap[SIZE],
pos[SIZE],home[SIZE],opt[SIZE];
//hep[i] 表示用顺序数组储存的堆 heap 中第 i 个元素的值
//pos[i] 表示 opt[i] 在堆 heap中的位置,即 heap[pos[i]]=opt[i]
//home[i] 表示 heap[i] 在序列 opt 中的位置,即 opt[home[i]]=heap[i]
void swap(int i,int j)// 交换堆中的第 i 个和第 j 个元素
{
int tmp;
pos[home[i]]=j;
pos[home[j]]=i;
tmp=heap[i];
head[i]=head[j];
heap[j]=tmp;
tmp=home[i];
home[i]=home[j];
home[j]=tmp;
}
void add(int k)// 在堆中插入 opt[k]
{
int i;
r++;
heap[r]= ① ;
pos[k]=r;
② ;
i=r;
while( (i>1) && (heap[i]<heap[i/2]) )
{
swap(i,i/2);
i/=2;
}
}
void remove(int k)// 在堆中删除 opt[k]
{
int i,j;
i=pos[k];
swap(i,r);;
r--;
if(i==r+1)
return ;
while( (i>1)&&(heap[i]<heap[i/2]) )
{
swap(i,i/2);
i/=2;
}
while(i+i<=r)
{
if( (i+i+1<=r) && (heap[i+i+1]<heap[i+i]) )
j=i+i+1;
else
③ ;
if(hea[i]>heap[j])
{
④ ;
i=j;
}
else
break;
}
}
int main()
{
int i;
cin>>n>>m;
for(i=1;i<=n;i+++)
cin>>value[i];
r=0;
for(i=1;i<=m;i++)
{
opt[i]=value[i];
add(i);
}
for(i=m+1;i<=n;i++)
{
opt[i]= ⑤ ;
remove( ⑥ );
add(i);
}
cout<<heap[1]<<endl;
return 0;
}每份考卷都有一个 8 位二进制序列号。当且仅当一个序列号含有偶数个 1 时,它才是有效的。例如,00000000、01010011都是有效的序列号,而 11111110 不是。那么,有效的序列号共有____个。
定义字符串的基本操作为:删除一个字符、插入一个字符和将一个字符修改成另一个字符这三种操作。将字符串 A 变成字符串 B 的最少操作步数,称为字符串 A 到字符串 B 的编辑距离。字符串 "ABCDEFG" 到字符串 "BADECG" 的编辑距离为____。
#include <iostream>
using namespace std;
int main(){
int i, n, m, ans;
cin>>n>>m;
i = n;
ans = 0;
while (i <= m){
ans += i;
i++;
}
cout<<ans<<endl;
return 0;
}输入: 10 20
输出: _________
#include <iostream>
#include <string>
using namespace std;
int main(){
string map = "22233344455566677778889999";
string tel;
int i;
cin>>tel;
for (i = 0; i < tel.length(); i++)
if ((tel[i] >= '0') && (tel[i] <= '9'))
cout<<tel[i];
else if ((tel[i] >= 'A') && (tel[i] <= 'Z'))
cout<<map[tel[i] - 'A'];
cout<<endl;
return 0;
}输入: CCF-NOIP-2011
输出: _______________
#include <iostream>
#include <cstring>
using namespace std;
const int SIZE = 100;
int main(){
int n, i, sum, x, a[SIZE];
cin>>n;
memset(a, 0, sizeof(a));
for (i = 1; i <= n; i++) {
cin>>x;
a[x]++;
}
i = 0; sum = 0;
while (sum < (n / 2 + 1)) {
i++;
sum += a[i];
}
cout<<i<<endl;
return 0;
}输入:
11
4 5 6 6 4 3 3 2 3 2 1
输出:________
#include <iostream>
using namespace std;
int solve(int n, int m){Preferences
int i, sum;
if (m == 1) return 1;
sum = 0;
for (i = 1; i < n; i++)
sum += solve(i, m - 1);
return sum;
}
int main(){
int n, m;
cin>>n>>m;
cout<<solve(n, m)<<endl;
return 0;
}输入: 7 4
输出: _________
(子矩阵) 给输入一个 n1*m1 的矩阵 a,和 n2*m2 的矩阵 b,问 a 中是否存在子矩阵和 b 相等。 若存在,输出所有子矩阵左上角的坐标:若不存在输出“ There is no answer ”。
#include <iostream>
using namespace std;
const int SIZE = 50;
int n1, m1, n2, m2, a[SIZE][SIZE], b[SIZE][SIZE];
int main(){
int i, j, k1, k2;
bool good, haveAns;
cin>>n1>>m1;
for (i = 1; i <= n1; i++)
for (j = 1; j <= m1; j++)
cin>>a[i][j];
cin>>n2>>m2;
for (i = 1; i <= n2; i++)
for (j = 1; j <= m2; j++)
①;
haveAns = false;
for (i = 1; i <= n1 - n2 + 1; i++)
for (j = 1; j <= ②; j++){
③;
for (k1 = 1; k1 <= n2; k1++)
for(k2 = 1; k2 <= ④; k2++) {
if (a[i + k1 - 1][j + k2 - 1] != b[k1][k2])
good = false;
}
if (good) {
cout<<i<<' '<<j<<endl;
⑤;
}
}
if (!haveAns)
cout<<"There is no answer"<<endl;
return 0;
}( 大整数开方 ) 输入一个正整数 n(1≤n≤10100),试用二分法计算它的平方根的整数部分。
#include <iostream>
#include <string>
using namespace std;
const int SIZE = 200;
struct hugeint {
int len, num[SIZE];
};
//其中 len 表示大整数的位数;num[1]表示个位、num[2]表示十位,以此类推
hugeint times(hugeint a, hugeint b) {
//计算大整数 a 和 b 的乘积
int i, j; hugeint ans;
memset(ans.num, 0, sizeof(ans.num));
for (i = 1; i <= a.len; i++)
for (j = 1; j <= b.len; j++)
①+= a.num[i] * b.num[j];
for (i = 1; i <= a.len + b.len; i++) {
ans.num[i + 1] += ans.num[i] / 10;
②;
}
if (ans.num[a.len + b.len] > 0)
ans.len = a.len + b.len;
else
ans.len = a.len + b.len - 1;
return ans;
}
hugeint add(hugeint a, hugeint b){
//计算大整数 a 和 b 的和
int i; hugeint ans;
memset(ans.num, 0, sizeof(ans.num));
if (a.len > b.len)
ans.len = a.len;
else
ans.len = b.len;
for (i = 1; i <= ans.len; i++) {
ans.num[i] +=③;
ans.num[i + 1] += ans.num[i] / 10;
ans.num[i] %= 10;
}
if (ans.num[ans.len + 1] > 0) ans.len++;
return ans;
}
hugeint average(hugeint a, hugeint b){
//计算大整数 a 和 b 的平均数的整数部分
int i; hugeint ans;
ans= add(a, b);
for(i = ans.len; i >= 2; i--) {
ans.num[i - 1] += (④) * 10;
ans.num[i] /= 2;
}
ans.num[1] /= 2;
if (ans.num[ans.len] == 0) ans.len--;
return ans;
}
hugeint plustwo(hugeint a) {
//计算大整数 a 加 2 后的结果
int i; hugeint ans;
ans = a;
ans.num[1] += 2;
i = 1;
While ((i <= ans.len) && (ans.num[i] >= 10)) {
ans.num[i + 1] += ans.num[i] / 10;
ans.num[i] %= 10;
i++;
}
if (ans.num[ans.len + 1] > 0)⑤;
return ans;
}
bool over(hugeint a, hugeint b){
//若大整数 a>b 则返回 true,否则返回 false
int i;
if (⑥) return false;
if (a.len > b.len) return true;
for (i = a.len; i >= 1; i--) {
if (a.num[i] < b.num[i])return false;
if (a.num[i] > b.num[i]) return true;
}
return false;
}
int main(){
string s;
int i;
hugeint target, left, middle, right;
cin>>s;
memset(target.num, 0, sizeof(target.num));
target.len = s.length();
for (i = 1; i <= target.len; i++)
target.num[i]= s[target.len - i] - ⑦;
memset(left.num, 0, sizeof(left.num));
left.len = 1;
left.num[1] = 1;
right = target;
do {
middle = average(left, right);
if (over(⑧))right = middle;
else left = middle;
} while (!over(plustwo(left), right));
for (i = left.len; i >= 1; i--)
cout<<left.num[i];
cout<<endl;
return 0;
}平面图是可以画在平面上、且它的边仅在顶点上才能相交的简单无向 图。 4 个顶点的平面图至多有 6 条边,如右图所示。那么, 5 个顶点的平面 图至多有 ________ 条边。

定义一种字符串操作,一次可以将其中一个元素移到任意位置。举例说明,对于字符 串”BCA”,可以将 A 移到 B 之前,变成字符串 ”ABC”。如果要将字符串 ”DACHEBGIF ”变成 "ABCDEFGHI" ,最少需要 ________ 次操作。
#include <iostream>
#include <cstring>
using namespace std;
const int SIZE = 100;
int main(){
int n, i, sum, x, a[SIZE];
cin>>n;
memset(a, 0, sizeof(a));
for (i = 1; i <= n; i++) {
cin>>x;
a[x]++;
}
i = 0; sum = 0;
while (sum < (n / 2 + 1)) {
i++;
sum += a[i];
}
cout<<i<<endl;
return 0;
}输入:
11
4 5 6 6 4 3 3 2 3 2 1
输出: _________
#include <iostream>
using namespace std;
int n;
void f2(int x, int y);
void f1(int x, int y){
if (x < n)f2(y, x + y);
}
void f2(int x, int y){
cout<<x<<' ';
f1(y, x + y);
}
int main(){
cin>>n;
f1(0, 1);
return 0;
}输入: 30
输出: _________
#include <iostream>
using namespace std;
const int V = 100;
int n, m, ans, e[V][V];
bool visited[V];
void dfs(int x, int len){
int i;
visited[x] = true;
if (len > ans)ans = len;
for (i = 1; i <= n; i++)
if ((! visited[i]) && (e[x][i] != -1))
dfs(i, len + e[x][i]);
visited[x] = false;
}
int main(){
int i, j, a, b, c;
cin>>n>>m;
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
e[i][j] = -1;
for (i = 1; i <= m; i++){
cin>>a>>b>>c;
e[a][b] = c;
e[b][a] = c;
}
for (i = 1; i <= n; i++)
visited[i] = false;
ans = 0;
for (i = 1; i <= n; i++)
dfs(i, 0);
cout<<ans<<endl;
return 0;
}输入:
4 6
1 2 10
2 3 20
3 4 30
4 1 40
1 3 50
2 4 60
输出:________
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
const int SIZE = 10000;
const int LENGTH = 10;
int n, m, a[SIZE][LENGTH];
int h(int u, int v){
int ans, i;
ans = 0;
for (i = 1; i <= n; i++)
if (a[u][i] != a[v][i])
ans++;
return ans;
}
int main(){
int sum, i, j;
cin>>n;
memset(a, 0, sizeof(a));
m = 1;
while (1){
i = 1;
while ((i <= n) && (a[m][i] == 1))
i++;
if (i > n) break;
m++;
a[m][i] = 1;
for (j = i + 1; j <= n; j++)
a[m][j] = a[m - 1][j];
}
sum = 0;
for (i = 1; i <= m; i++)
for (j = 1; j <= m; j++)
sum += h(i, j);
cout<<sum<<endl;
return 0;
}输入: 7
输出:______
(大整数开方 )输入一个正整数 n(1<=n<10 100 ),试用二分法计算它的平方根的整 数部分。
【程序清单】
#include <iostream>
#include <string>
using namespace std;
const int SIZE = 200;
struct hugeint {
int len, num[SIZE];
};
//其中 len 表示大整数的位数;num[1]表示个位、num[2]表示十位,以此类推
hugeint times(hugeint a, hugeint b) {
//计算大整数 a 和 b 的乘积
int i, j; hugeint ans;
memset(ans.num, 0, sizeof(ans.num));
for (i = 1; i <= a.len; i++)
for (j = 1; j <= b.len; j++)
①+= a.num[i] * b.num[j];
for (i = 1; i <= a.len + b.len; i++) {
ans.num[i + 1] += ans.num[i] / 10;
②;
}
if (ans.num[a.len + b.len] > 0)
ans.len = a.len + b.len;
else
ans.len = a.len + b.len - 1;
return ans;
}
hugeint add(hugeint a, hugeint b){
//计算大整数 a 和 b 的和
int i; hugeint ans;
memset(ans.num, 0, sizeof(ans.num));
if (a.len > b.len)
ans.len = a.len;
else
ans.len = b.len;
for (i = 1; i <= ans.len; i++) {
ans.num[i] +=③;
ans.num[i + 1] += ans.num[i] / 10;
ans.num[i] %= 10;
}
if (ans.num[ans.len + 1] > 0) ans.len++;
return ans;
}
hugeint average(hugeint a, hugeint b){
//计算大整数 a 和 b 的平均数的整数部分
int i; hugeint ans;
ans= add(a, b);
for(i = ans.len; i >= 2; i--) {
ans.num[i - 1] += (④) * 10;
ans.num[i] /= 2;
}
ans.num[1] /= 2;
if (ans.num[ans.len] == 0) ans.len--;
return ans;
}
hugeint plustwo(hugeint a) {
//计算大整数 a 加 2 后的结果
int i; hugeint ans;
ans = a;
ans.num[1] += 2;
i = 1;
While ((i <= ans.len) && (ans.num[i] >= 10)) {
ans.num[i + 1] += ans.num[i] / 10;
ans.num[i] %= 10;
i++;
}
if (ans.num[ans.len + 1] > 0)⑤;
return ans;
}
bool over(hugeint a, hugeint b){
//若大整数 a>b 则返回 true,否则返回 false
int i;
if (⑥) return false;
if (a.len > b.len) return true;
for (i = a.len; i >= 1; i--) {
if (a.num[i] < b.num[i])return false;
if (a.num[i] > b.num[i]) return true;
}
return false;
}
int main(){
string s;
int i;
hugeint target, left, middle, right;
cin>>s;
memset(target.num, 0, sizeof(target.num));
target.len = s.length();
for (i = 1; i <= target.len; i++)
target.num[i]= s[target.len - i] - ⑦;
memset(left.num, 0, sizeof(left.num));
left.len = 1;
left.num[1] = 1;
right = target;
do {
middle = average(left, right);
if (over(⑧))right = middle;
else left = middle;
} while (!over(plustwo(left), right));
for (i = left.len; i >= 1; i--)
cout<<left.num[i];
cout<<endl;
return 0;
}(笛卡尔树 )对于一个给定的两两不等的正整数序列, 笛卡尔树是这样的一棵二叉树。首先,它是一个最小堆,即 除了根结点外, 每个结点的权值都大于父结点的权值; 其次, 它的中序遍历恰好就是给定的序列。例如,对于序列 7、2 、12 、1、10 、5、15 、3 ,下图就是一棵对应的笛卡尔树。 现输入序列的规模 n(1<=n<100 ) 和序列的 n 个元素,试求对应的笛卡尔树的深度 d(根节点深度为 1),以及有多少个叶节 点的深度为 d 。

【程序清单】
#include <iostream>
using namespace std;
const int SIZE = 100+5;
const int INFINITY = 1000000;
int n, a[SIZE], maxDeep, num;
void solve(int left, int right, int deep){
int i, j, min;
if (deep > maxDeep) {
maxDeep = deep;
num = 1;
}else if (deep == maxDeep)
①;
min = INFINITY;
for (i = left; i <= right; i++)
if (min > a[i]) {
min = a[i];
②;
}
if(left < j)③;
if(j < right)④;
}
int main(){
int i;
cin>>n;
for (i = 1; i <= n; i++)
cin>>a[i];
maxDeep = 0;
solve(1, n, 1);
cout<<maxDeep<<' '<<num<<endl;
return 0;
}如果平面上任取 n 个整点(横纵坐标都是整数),其中一定存在两个点,它们连线的中点也是整点,那么 n 至少是____。
在 NOI 期间,主办单位为了欢迎来自各国的选手,举行了盛大的晚宴。在第 十八桌,有 5 名大陆选手和 5 名港澳选手共同进膳。 为了增进交流, 他们决定相 隔就坐,即每个大陆选手左右旁都是港澳选手, 每个港澳选手左右旁都是大陆选 手。那么,这一桌一共有 _______种不同的就坐方案。注:如果在两个方案 中,每个选手左右相邻的选手相同 ,则视为同一种方案。
#include <iostream>
using namespace std;
int a, b, c, d, e, ans;
int main(){
cin>>a>>b>>c;
d = a+b;
e = b+c;
ans = d+e;
cout<<ans<<endl;
}输入: 1 2 5
输出: _______