noip 2008 提高组初赛订正

单选

5.将数组{8, 23, 4, 16, 77, -5, 53, 100}中的元素按从大到小的顺序排列,每次可以交换任意两个元素,最少需要交换( )次。
A. 4 B. 5 C. 6 D. 7 E. 8
将某个数向它的目标位置连一条边,那么最终会形成几个环,对某一个有n个点的环,需要n-1步将其变成n个自环,故 a n s = n − n u m l o o p ans=n-num_{loop} ans=nnumloop

这题的图如下
在这里插入图片描述

多选

12.计算机在工作过程中,若突然停电,( )中的信息不会丢失。
A. 硬盘 B. CPU C.ROM D. RAM

AC肯定不会丢失,D(内存,包括cache)肯定会丢失。CPU的寄存器好像有断电保持和断电不保持,这里可能把CPU认为是处理信息而不存储信息

数学题

2.书架上有21本书,编号从1到21,从其中选4本,其中每两本的编号都不相邻的选法一共有______种。

方法一:f[i][j]表示前i个位置,放j个球(且有球放在第i个位置上)的方案数,
f [ i ] [ j ] = ∑ k = 0 k < = i − 2 f [ k ] [ j − 1 ] f[i][j]=\sum_{k=0}^{k<=i-2} f[k][j-1] f[i][j]=k=0k<=i2f[k][j1],列表如下,

j\i123456789101112131415161718192021
1111111111111111111111
20012345678910111213141516171819
3000013610152128364555667891105120136153
4000000141020355684120165220286364455560680

答案是最后一行的和,3060

方法二:可以看出这个答案是1~15的前缀和的前缀和的前缀和(没错,是三个前缀和),
第一遍前缀和 a [ n ] = n ∗ ( n + 1 ) / 2 a[n]=n*(n+1)/2 a[n]=n(n+1)/2
第二遍前缀和 b [ n ] = ∑ j = 1 j ≤ n j ∗ ( j + 1 ) / 2 = ∑ j = 1 j ≤ n j 2 / 2 + n ∗ ( n + 1 ) / 4 b[n]=\sum_{j=1}^{j \leq n} j*(j+1)/2=\sum_{j=1}^{j \leq n}j^2/2+n*(n+1)/4 b[n]=j=1jnj(j+1)/2=j=1jnj2/2+n(n+1)/4
下一步化简需要用到二次方和公式,具体推导用 ( n + 1 ) 3 − 1 (n+1)^3-1 (n+1)31展开来做。
∴ b [ n ] = n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) / 12 + n ∗ ( n + 1 ) / 4 = n ∗ ( n + 1 ) ∗ ( n + 2 ) / 6 \therefore b[n]=n*(n+1)*(2*n+1)/12+n*(n+1)/4=n*(n+1)*(n+2)/6 b[n]=n(n+1)(2n+1)/12+n(n+1)/4=n(n+1)(n+2)/6
再求前缀和! c [ n ] = 1 6 ∗ ∑ ( j 3 + 3 ∗ j 2 + 2 ∗ j ) c[n]=\frac{1}{6}*\sum (j^3+3*j^2+2*j) c[n]=61(j3+3j2+2j)
愉快地用上立方和和平方和公式还有普通求和公式,得到
c [ n ] = 1 6 ∗ ( n 2 ∗ ( n + 1 ) 2 / 4 + 3 ∗ n ∗ ( n + 1 ) ∗ ( 2 ∗ n + 1 ) / 6 + 2 ∗ n ∗ ( n + 1 ) / 2 ) c[n]=\frac{1}{6}*(n^2*(n+1)^2/4+3*n*(n+1)*(2*n+1)/6+2*n*(n+1)/2) c[n]=61(n2(n+1)2/4+3n(n+1)(2n+1)/6+2n(n+1)/2)
= n ∗ ( n + 1 ) ∗ ( n 2 + 5 ∗ n + 6 ) / 24 =n*(n+1)*(n^2+5*n+6)/24 =n(n+1)(n2+5n+6)/24
将n=15带入,得到c[15]=3060
话说公式这种东西一定要反复检查,以我现在的数学水平一遍是不可能算对的

方法三:这题按理说是要用组合数做的
可以把前三本书和他们后面的一个空格绑定起来,或者可以看成用17个空格把4本书隔开,结果就是 C 18 4 = 3060 C_{18}^{4}=3060 C184=3060

看程序写结果

 #include<iostream>
	using namespace std;
	int main()
	{
		int i, a, b, c, d, f[4];
		for(i = 0; i < 4; i++) cin >> f[i];
		a = f[0] + f[1] + f[2] + f[3];
		a = a / f[0];//把除号看成取模,眼瞎。"/" != "%'!!!
		b = f[0] + f[2] + f[3];
		b = b / a;//这里也看错
		c = (b * f[1] + a) / f[2];
		d = f[(b / c ) % 4];
		if(f[(a + b + c + d) % 4] > f[2])
			cout << a + b<< endl;
		else cout << c + d << endl;
		return 0;
}

纯手膜,考试的时候一定要多膜几遍!!!一遍绝对做不对!!!
ans=23

#include<iostream>
using namespace std;
void f(int a, int b, int c)
{
	cout << a << b << c <</;
	if(a == 3 && b == 2 && c == 1)
		return;
	if(b < c)
		f(a, c, b);
	else if(a < b)
	{
		if(a < c)
			f(c, a, b);
		else
			f(b, c, a);
	}
}

int main()
{
	int a, b, c;
	cin >> a >> b >> c;
	f(a, b, c);
	cout << endl;
	return 0;
}

输入: 1 3 2

(╯°Д°)╯︵ ┻━┻要注意输出最后也是有斜杠的,对于这种写在循环或者跟在某个要多次处理的语句后面的字符,一定要非常小心,不然8分丢不起。
wrong ans = " 132/213/231/312/321"
accepted = “132/213/231/312/321/”

程序填空

1.(找第k大的数) 给定一个长度为1,000,000的无序正整数序列,以及另一个数n(1<=n<=1000000),接下来以类似快速排序的方法找到序列中第n大的数(关于第n大的数:例如序列{1,2,3,4,5,6}中第3大的数是4)。

#include <iostream>
using namespace std;

int a[1000001],n,ans = -1;
void swap(int &a,int &b)
{
	int c;
	c = a; a = b;	b = c;
}

int FindKth(int left, int right, int n)
{
	int tmp,value,i,j;
	if (left == right) return left;
	tmp = rand()% (right - left) + left;
	swap(a[tmp],a[left]);
	value =          ①         
	i = left;
	j = right;
	while (i < j)
	{
		while (i < j &&) j --;
		if (i < j) {a[i] = a[j]; i ++;} else break;
		while (i < j &&) i ++;
		if (i < j) {a[j] = a[i]; j --;} else break;
	}if (i < n) return  FindKth();
	if (i > n) returnreturn i;
}

int main()
{
	int i;
	int m = 1000000;
	for (i = 1;i <= m;i ++)
		cin >> a[i];
	cin >> n;
	ans = FindKth(1,m,n);
	cout << a[ans];
     return 0;
}

首先这是一个快拍,但是他的打法非常达克,不是平常经常打的两个指针的,而是填坑的。然后注意是从大到小排序而不是从小到大,和习惯性的思维不同。而且判断大小的时候等于取或不取都是可行的。注意了这几点就可以满分,然而。。。

总结

实际得分:51.5

加上眼瞎扣分,算错扣分,粗心扣分:86

差距有点可怕。真正比赛的时候一定要检查,有时间就一直算吧,反正草稿纸是公家的。

返回顶部

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: NOIP2008 普及复赛试题是中国国家信息学奥林匹克选手选拔赛的试题之一,比较经典且有一定难度。以下是对该试题的解答。 本次试题主要有三道题目,分别是小数排列、整数取位和检测型括号序列。 小数排列这道题要求给定一个正整数 n,求小于 n 的所有符合要求的小数的个数。解决这一题的方法是利用排列合的知识,找出符合要求的小数的模式并计算其个数。具体的代码实现就需要对 n 进行拆分,计算个位数、十位数和百位数的可能情况并相乘即可得到结果。 整数取位这道题要求给定一个整数 n 和一个非负整数 m,求 n 的第 m 个数字。解决这一题的方法是将整数 n 转化为字符串,然后通过字符串的索引来获取第 m 个数字。 检测型括号序列这道题要求判断给定的一个仅包含左右括号的字符串是否是合法的括号序列。解决这一题的方法是使用栈的数据结构,遍历字符串,对于每个遇到的左括号,将其压入栈中;对于每个遇到的右括号,检查栈顶元素是否为对应的左括号,若是,则弹出栈顶元素,否则返回不合法。 以上就是对 NOIP2008 普及复赛试题的简要解答,其中涉及到的算法和数据结构是编程中比较常见的基础知识,通过理解和掌握这些知识,可以帮助我们更好地解决类似的编程问题。 ### 回答2: NOIP(全国青少年信息学奥林匹克竞赛)是中国举办的一项信息学竞赛活动。2008年,NOIP举办了普及复赛。以下是对该年度复赛试题进行的解答。 复赛试题一共有三大题目,分别涉及到图的遍历、数学运算和字符串处理。 第一题是关于图的遍历的。题目给出一张有向图和一个起始节点,要求按照拓扑排序的原则遍历整个图,并输出遍历的结果。拓扑排序是一种将有向无环图的顶点进行排序的算法,具体实现可以使用DFS或者BFS。根据题目给出的起始节点,我们可以使用DFS从该节点开始遍历图,并使用一个栈来存储遍历的结果。 第二题是一个数学运算的题目,要求计算一个给定数的乘方结果的各位数字之和。这题可以通过将给定数转化为字符串,然后对字符串中的每位数字进行相加来解答。也可以将给定数分解为各位数字相加的形式。具体实现上可以使用循环或者递归的方式。 第三题是一个关于字符串处理的任务,要求将输入字符串中的数字字符提取出来,并计算所有数字的平均值。这个问题可以通过遍历字符串的方式来解决。对于每个字符,我们判断是否为数字字符,是的话就将其转换为数字并累加到一个总和上。最后将总和除以数字字符的个数,得到平均值。 总体来说,NOIP 2008 普及复赛试题涵盖了图的遍历、数学运算和字符串处理的内容。通过解答这些问题,可以增强对这些概念的理解,并提升解决实际问题的能力。 ### 回答3: NOIP2008普及复赛试题是一道考察动态规划和递归思想的题目。题目给出了一个整数n,要求计算出整数1到n的所有排列中,满足以下条件的排列的个数: 1.相邻两个数的差的绝对值不能等于1; 2.排列中的数不能重复。 首先,我们需要定义一个函数f(n),表示整数1到n的满足条件的排列的个数。我们可以将这个问题转化为子问题,即如何计算f(n-1)和f(n-2)等。 根据题目要求,我们可以发现f(n)的值由两部分成:一部分是以n结尾的满足条件的排列的个数,另一部分是不以n结尾的满足条件的排列的个数。 对于第一部分,即以n结尾的排列,我们可以将其分为两种情况:n和n-2相邻,以及n和n-2不相邻。如果n和n-2相邻,那么有f(n-2)种情况。如果n和n-2不相邻,那么可以在以n-1结尾的排列后面加上n,所以有f(n-1)种情况。因此,以n结尾的满足条件的排列的个数为f(n) = f(n-1) + f(n-2)。 对于第二部分,即不以n结尾的排列,其个数就是f(n-1)。 所以,f(n) = f(n-1) + f(n-2) + f(n-1) = 2*f(n-1) + f(n-2)。 基本情况是当n=1时,满足条件的排列只有1个,即f(1)=1;当n=2时,满足条件的排列有2个,即f(2)=2。 通过递推,可以得到整个解空间中满足条件的排列的个数。 在编程实现时,可以使用动态规划来解决这道题。先定义一个大小为n+1的数dp,dp[i]表示整数1到i的满足条件的排列的个数。然后,通过循环从3到n,依次计算dp[i]的值,最后返回dp[n]即可。 总结起来,这道题是通过递推和动态规划的思想来计算满足条件的排列的个数。通过定义状态转移方程,将大问题转化为小问题,最后通过循环计算得出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值