NOIP真题

第581题

(哥德巴赫猜想) 哥德巴赫猜想是指,任一大于 2 的偶数都可写成两个质数之和。迄今 为止, 这仍然是一个著名的世界难题,被誉为数学王冠上的明珠。 试编写程序,验证任一大 于 2 且不超过 n 的偶数都能写成两个质数之和。

#include<iostream>
using namespace std;
int main() {
    const int SIZE = 1000;
    int n, r, p[SIZE], i, j, k, ans;
    bool tmp;
    cin>>n;
    r = 1;
    p[1] = 2;
    for (i = 3; i <= n; i++) {
             ①   _______;
        for (j = 1; j <= r; j++)
            if (i %  ② ______) {
                tmp = false;
                break;
            }
        if (tmp) {
            r++;
                ③_________  
 
        }
    }
    ans = 0;
    for (i = 2; i <= n / 2; i++) {  // i=n/2 表示缩小范围,排除重复情况。
        tmp = false;
        for (j = 1; j <= r; j++)
            for (k = j; k <= r; k++)
                if (i + i ==  ④ _______   ) {
                    tmp = true;
                    break;
                }
        if (tmp)
            ans++;
    }
    cout<<ans<<endl;
    return 0;
}若输入 n 为 2010 ,则输出 ⑤ _______   时表示验证成功,即大于 2 且不超过 2010 的偶数都 满足哥德巴赫猜想。


第582题

(过河问题) 在一个月黑风高的夜晚,有一群人在河的右岸,想通过唯一的一根独木桥 走到河的左岸。 在这伸手不见五指的黑夜里, 过桥时必须借助灯光来照明, 很不幸的是,他 们只有一盏灯。 另外,独木桥上最多承受两个人同时经过,否则将会坍塌。 每个人单独过桥 都需要一定的时间,不同的人需要的时间可能不同。两个人一起过桥时,由于只有一盏灯,所以需要的时间是较慢的那个人单独过桥时所花的时间。现输入 n( 2≤n≤100)和这 n 个 人单独过桥时需要的时间,请计算总共最少需要多少时间,他们才能全部到达河的左岸。 例如,有 3 个人甲、乙、丙,他们单独过桥的时间分别为 1、 2、4,则总共最少需要 的时间为 7 。具体方法是:甲、乙一起过桥到河的左岸,甲单独回到河的右岸将灯带回,然 后甲、丙再一起过桥到河的左岸,总时间为 2+1+4=7 。

#include<iostream>
using namespace std;
const int SIZE = 100;
const int INFINITY = 10000;
const bool LEFT = true;
const bool RIGHT = false;
const bool LEFT_TO_RIGHT = true;
const bool RIGHT_TO_LEFT = false;
int n, hour[SIZE];  //存放每个人的过河时间
bool pos[SIZE];  
int max(int a, int b) {
    if (a > b)
        return a;
    else
        return b;
}
int go(bool stage) {
    int i, j, num, tmp, ans;
    if (stage == RIGHT_TO_LEFT) {  
        num = 0;
        ans = 0;
        for (i = 1; i <= n; i++)
            if (pos[i] == RIGHT) { 
                num++;   //人数加1
                if (hour[i] > ans) 
                    ans = hour[i];  //ans保留了最长的过桥时间,
            }
        if ( ① __________    )
            return ans;
        ans = INFINITY;
        for (i = 1; i <= n - 1; i++)
            if (pos[i] == RIGHT)  //如果这个人在右侧
                for (j = i + 1; j <= n; j++)
                    if (pos[j] == RIGHT) {
                        pos[i] = LEFT;
                        pos[j] = LEFT;
                        tmp = max(hour[i], hour[j]) +  ② __________) ;
                        if (tmp < ans)
                            ans = tmp;
                        pos[i] = RIGHT;
                        pos[j] = RIGHT;
                    }
        return ans;
    }
    if (stage == LEFT_TO_RIGHT) {
        ans = INFINITY;
        for (i = 1; i <= n; i++)
            if (  ③_________) {
                pos[i] = RIGHT;
                tmp =  ④ _________;
                if (tmp < ans)
                    ans = tmp;
                              ⑤__________   ;
 
            }
        return ans;
    }
    return 0;
}
int main() {
    int i;
    cin>>n;
    for (i = 1; i <=n; i++) {
        cin>>hour[i];
        pos[i] = RIGHT;  //pos是记录每个元素所处的位置。
    }
    cout<<go(RIGHT_TO_LEFT)<<endl;  //初始状态RIGHT_TO_LEFT
    return 0;
}


第583题

LZW 编码是一种自适应词典编码。在编码的过程中,开始时只有一部基础构造元素的编 码词典, 如果在编码的过程中遇到一个新的词条, 则该词条及一个新的编码会被追加到词典 中,并用于后继信息的编码。 举例说明,考虑一个待编码的信息串:“ xyx yy yy xyx ”。初始词典只有 3 个条目, 第一个为 x,编码为 1;第二个为 y,编码为 2;第三个为空格,编码为 3;于是串“ xyx”的 编码为 1-2-1 (其中 -为编码分隔符),加上后面的一个空格就是 1-2-1-3 。但由于有了一个 空格,我们就知道前面的“ xyx”是一个单词,而由于该单词没有在词典中,我们就可以自 适应的把这个词条添加到词典里,编码为 4,然后按照新的词典对后继信息进行编码,以此 类推。于是,最后得到编码: 1-2-1-3-2-2-3-5-3-4 。 我们可以看到,信息被压缩了。压缩好的信息传递到接受方,接收方也只要根据基础 词典就可以完成对该序列的完全恢复。 解码过程是编码过程的逆操作。 现在已知初始词典的 3 个条目如上述,接收端收到的编码信息为 2-2-1-2-3-1-1-3-4-3-1-2-1-3-5-3-6 ,则解码 后的信息串是” ______________________________________________________________ ”。

第584题

无向图 G 有 7 个顶点,若不存在奇数条边构成的简单回路,则它至多有 __________ 条 边。

第585题

记 T 为一队列初始为空现有 n 个总和不超过 32 的正整数依次入队如果无论这些数具 体为何值都能找到一种出队的方式使得存在某个时刻队列 T 中的数之和恰好为 9 那么 n 的最小值是 ________________。

第586题
#include <stdio.h>
#define SIZE 10
int main() 
{
	int data[SIZE], i, j, cnt, n, m;// 定义 // 
	scanf("%d %d\n", &n, &m);// 输入 n 和 m,此处我们输入的是 5 和 2//
	for(i = 1; i <= n; i++)
		scanf("%d", &data[i]);// 再次输入 i 个数 data[1] =96 data[2]=-8 data[3]=0 data[4]=16 data[5]=87//
	for(i = 1; i <= n; i++) 
	{ //n=5//
		cnt = 0;
		for(j = 1; j<= n; j++)//n=5 ,data[1] =96 data[2]=-8 data[3]=0 data[4]= 16
		data[5]=87//
		if ((data[i] < data[j]) || (data[j] == data[i] && j< i))// 如果说 data[i]<data[j] ,或者说{data[j] 等于 data[i] ,同时 j 小于 i
		cnt++;//cnt 的数目加 1// 
		if(cnt == m)// 如果说 cnt 等于 m 等于 2,因为 cnt=2 ,即整个程序运行了两遍,也运行两遍,换句话说,只有恰好运行两遍的数字才能满足题意。假设, data[1]=96 ,与
		data[2]=-8 data[3]=0 data[4]= 16 data[5]=87 //比较大小时, 显然为最大, 不能比其他的数小,不满足条件 data[i] < data[j] ,同样, data[2]=-8 ,比它大的数有 3 个也不满足题意,
		data[3]=0 //比它大的数有 4 个,不合题意 data[4]= 16 ,比它大的数恰恰只有两个,满足题意,为所输出 //
		printf("%d\n", data[i]);// 输出 data[i]//
	}
	getch(); //(此语句在 windows 2000 以上系统用 winTC 编译 C 时需要加入,用以暂停查看屏幕)
	return 0;
}

输入: 5 2 

 96 -8 0 16 87 

输出: ______

第587题
#include <stdio.h>
#define SIZE 100
int main()
{
	int na, nb, a[SIZE], b[SIZE], i, j, k;// 定义 //
	scanf("%d\n", &na);// 输入 5,即 na=5//
	for (i = 1; i <= na; i++)
		scanf("%d", &a[i]);// 输入数字, a[1]=1. a[2]=3 a[3]=5 a[4]=7 a[5]=9//
	scanf("%d\n", &nb);// 输入数字 4//
	for (i = 1; i <= nb; i++)
		scanf("%d", &b[i]);// 同理,输入数字 b[1] =2 b[2] =6 b[3] =10 b[4] =14//
	i=1;
	j=1;
	while ((i <= na) && (j <= nb)) 
	{// 当 i 小于等于 na 时,并且 j 小于等于 nb 时候 //
		if (a[i] <= b[j]) 
		{// 如果说 a[i]大于 b[j]//
			printf("%d ", a[i]);// 输出 a[i]//
			i++;//i 增加 1//
		}
		else {
		printf("%d ", b[j]);// 否则输出 b[j]//
		j++;
		}
	}
	if (i <= na)// 如果 i 小于等于 na//
	for (k = i; k<= na; k++)// 循环 //
	printf("%d ", a[k]); //按照上面的循环条件输出数字 //
	if (j <= nb)
	for (k = j; k<= nb; k++)// 同理 //
	printf ("%d ", b[k]); 
	getch();
	return 0;
}

输入: 5

 1 3 5 7 9 

2 6 10 14 

输出:______

第588题
#include<iostream>
using namespace std;
const int NUM=5;
int r(int n)
{
	 int i;
	 if(n<=NUM)
	 return 0;
	 for(i=1;i<=NUM;i++)
	 if( r(n-i)<0)
	 return i;
	 return -1;
}
int main()
{
	 int n; 
	 cin>>n;
	 cout<<r(n)<<endl;
	 return 0;
}

输入: 16 

输出: ______________ 

第589题
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=100;
int n,m,r[SIZE];
bool map[SIZE][SIZE],found;
bool successful()
{
 int i;
 for(i=1;i<=n;i++)
 if(!map[r[i]][r[i%n+1]])
 return false;
 return true;
}
void swap(int *a,int *b)
{
 int t;
 t=*a;
 *a=*b;
 *b=t;
}
void perm(int left,int right)
{
 int i;
 if(found)
 return ;
 if(left>right)
 { 
 if(successful())
 {
 for(i=1;i<=n;i++)
 cout<<r[i]<<' ';
 found=true;
 }
 return ; 
 }
 for(i=left;i<=right;i++)
 {
 swap(r+left,r+i);
 perm(left+1,right);
 swap(r+left,r+i);
 }
}
int main()
{
 int x,y,i;
 cin>>n>>m;
 memset(map,false,sizeof(map));
 for(i=1;i<=m;i++)
 {
 cin>>x>>y;
 map[x][y]=true;
 map[y][x]=true;
 }
 for(i=1;i<=n;i++)
 r[i]=i;
 found=false;
 perm(1,n);
 if(!found)
 cout<<"No solution!"<<endl; 
 return 0;
}

输入: 9 12 

1 2 

2 3 

3 4 

4 5

5 6

6 1 

1 7

2 7

3 8 

4 8 

5 9 

6 9 

输出: _________

第590题

( 过河问题 ) 在一个月黑风高的夜晚 , 有一群人在河的右岸 , 想通过唯一的一根独木桥走到 河的左岸 . 在伸手不见五指的黑夜里 , 过桥时必须借照灯光来照明 , 不幸的是 , 他们只有一盏灯 . 另外, 独木桥上最多能承受两个人同时经过 , 否则将会坍塌 . 每个人单独过独木桥都需要一定 的时间 , 不同的人要的时间可能不同 . 两个人一起过独木桥时 , 由于只有一盏灯 , 所以需要的时 间是较慢的那个人单独过桥所花费的时间 . 现在输入 N(2<=N<1000)和这 N 个人单独过桥需要 的时间 , 请计算总共最少需要多少时间 , 他们才能全部到达河左岸 . 

例如, 有 3 个人甲、乙、丙 , 他们单独过桥的时间分别为 1、2、4, 则总共最少需要的时 间为 7. 具体方法是 : 甲、乙一起过桥到河的左岸 , 甲单独回到河的右岸将灯带回 , 然后甲、丙 在一起过桥到河的左岸 , 总时间为 2+1+4=7.

#include<iostream>
#include<cstring>
using namespace std;
const int SIZE=100;
const int INFINITY = 10000;
const bool LEFT=true;
const bool RIGHT =false; 
const bool LEFT_TO_RIGHT=true;
const bool RIGHT_TO_LEFT=false;
int n,hour[SIZE];
bool pos[SIZE];
int max(int a,int b)
{
 if(a>b)
 return a;
 else
 return b;
} 
int go(bool stage)
{
 int i,j,num,tmp,ans;
 if(stage==RIGHT_TO_LEFT)
 {
 num=0;
 ans=0;
 for(i=1;i<=n;i++)
 if(pos[i]==RIGHT)
 {
 num++;
 if( hour[i]>ans)
 ans=hour[i];
 }
 if( ① ) 
 return ans;
 ans=INFINITY;
 for(i=1;i<=n-1;i++)
 if(pos[i]==RIGHT) 
 for(j=i+1;j<=n;j++)
 if(pos[j]==RIGHT)
 {
 pos[i]=LEFT;
 pos[j]=LEFT;
 tmp=max(hour[i],hour[j])+ ② ;
 if(tmp<ans)
 ans=tmp;
 pos[i]=RIGHT;
 pos[j]=RIGHT;
 }
 return ans;
 }
 if(stage==LEFT_TO_RIGHT)
 {
 ans=INFINITY;
 for(i=1;i<=n;i++)
 if( ③ )
 {
 pos[i]=RIGHT;
 tmp= ④ ;
 if(tmp<ans)
 ans=tmp;
⑤ ;
 }
 return ans;
 }
 return 0;
}
int main() 
{
 int i;
 cin>>n;
 for(i=1;i<=n;i++)
 {
 cin>>hour[i];
 pos[i]=RIGHT;
 }
 cout<<go[RIGHT_TO_LEFT)<<endl;
 return 0;
}


第591题

(烽火传递) 烽火台又称烽燧,是重要的军事防御设施,一般建在险要处或交通要道上。 一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情。在 某两座城市之间有 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;
}


第592题

每份考卷都有一个 8 位二进制序列号。当且仅当一个序列号含有偶数个 1 时,它才是有效的。例如,00000000、01010011都是有效的序列号,而 11111110 不是。那么,有效的序列号共有____个。

第593题

定义字符串的基本操作为:删除一个字符、插入一个字符和将一个字符修改成另一个字符这三种操作。将字符串 A 变成字符串 B 的最少操作步数,称为字符串 A 到字符串 B 的编辑距离。字符串 "ABCDEFG" 到字符串 "BADECG" 的编辑距离为____。

第594题
#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 

输出: _________

第595题
#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 

输出: _______________

第596题
#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 

输出:________

第597题
#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 

输出: _________

第598题

(子矩阵) 给输入一个 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;
}


第599题

( 大整数开方 ) 输入一个正整数 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;
}


第600题

平面图是可以画在平面上、且它的边仅在顶点上才能相交的简单无向 图。 4 个顶点的平面图至多有 6 条边,如右图所示。那么, 5 个顶点的平面 图至多有 ________ 条边。

QQ截图20210120140835.png