1. 程式人生 > >noip 2008 提高組初賽訂正

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 &&