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}

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

多选

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] ,列表如下,

j\i 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
3 0 0 0 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153
4 0 0 0 0 0 0 1 4 10 20 35 56 84 120 165 220 286 364 455 560 680

答案是最后一行的和,3060

方法二:可以看出这个答案是1~15的前缀和的前缀和的前缀和(没错,是三个前缀和),
第一遍前缀和 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
下一步化简需要用到二次方和公式,具体推导用 ( n + 1 ) 3 1 (n+1)^3-1 展开来做。
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
再求前缀和! 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 ] = 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)
= n ( n + 1 ) ( n 2 + 5 n + 6 ) / 24 =n*(n+1)*(n^2+5*n+6)/24
将n=15带入,得到c[15]=3060
话说公式这种东西一定要反复检查,以我现在的数学水平一遍是不可能算对的

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

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

返回顶部

猜你喜欢

转载自blog.csdn.net/xyyxyyx/article/details/82966378
今日推荐