NOIP2018初赛复习(7)-阅读程序写结果
2018-08-25 13:54
这部分其实很容易,目的几乎是送分,而且占的分数很多,但得分率却不见得高。很容易不明不白的就把分(全)丢了!!! 这部分程序考3个方面:
1. 程序设计语言本身,如循环、递归、值型参和变量型参数、跟踪变量等;
2. 归纳和数学运算能力; 3. 是否掌握了一些常用算法(程序段)的框架;
4. 细心、耐心等心理品质;灵感+编程的量等; 一般做这类题目的核心是找程序目的:
即这个程序想干什么。迄今为止考过的题目还没有“乱写”的,总有一点“写作目的”的。抓住了它,不仅得出答案变得很容易了,而且对自己的结果也会比较有信心。
一般的解题步骤如下: 1. 从总体上通读程序,大致把握程序的目的和算法;
2. 猜测变量的作用,跟踪主要变量值的变化(列表),找出规律;
3. 将程序分段,理清每一小段的作用和目的(灵感+关键表达式和语句的领会);
4. 看清输入、按照输出格式,写出结果; 5. 带着得到的结果回到程序进行检查;
例题(NOIP2017提高组) 1. #include using namespacestd; int g(int m, intn,
int x){
int ans = 0;
int i;
if( n == 1)
return 1;
for (i=x; i <=m/n; i++)
ans += g(m –i, n-1, i);
return ans; } int main() { int t, m, n; cin >> m >> n;
cout << g(m, n, 0) << endl; return 0; } 输入: 8 4
输出: 15
解析:就是一个简单的递推题,大家只要自己认真的推算一遍即可,一定要找一张干净的草稿纸,然后有条理的写,这样就能很容易的算出来了。博主第一遍就因为很随便,算出的答案是14,后来写完后面的题,回头找老师又要了几张草稿纸,重算一遍,才算正确。
2. #include using namespacestd; int main() { int n, i, j, x, y, nx,
ny; int a[40][40]; for (i = 0; i< 40; i++)
for (j = 0;j< 40; j++)
a[i][j]= 0; cin >> n; y = 0; x = n-1; n = 2*n-1; for (i = 1;
i <= n*n; i++){ a[y][x] =i;
ny = (y-1+n)%n;
nx = (x+1)%n; if ((y == 0 && x == n-1) || a[ny][nx] !=0)
y= y+1; else
{y = ny; x = nx;}
}
for (j = 0; j < n; j++)
cout << a[0][j]<< “”; cout << endl; return 0; }
输入: 3 输出: 17 24 1 8 15 解析:就是一个幻方。
一眼看透本质后就很简单了,只要自己把幻方填上就行。
这里说一下幻方的定义,就是将1到n*n这些整数填入n*n的方格表,使得每一行、每一列、对角线上的数之和为同一值。
填的方法也很简单,我在小学时就和我的(女)同学探讨过奇数规模的幻方的填写方法(嗯?奇怪的强调……),具体方法如下:
首先将1写在第一行的中间。 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N):
1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列;
2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行;
3.若(K−1)在第一行最后一列,则将K填在(K−1)的正下方;
4.若(K−1)既不在第一行,也不在最后一列,如果(K−1)的右上方还未填数,则将K填在(K−1)的右上方,否则将K填在(K−1)的正下方。
这样就能写出一个幻方了,然后输出第一行即可。 还有注意,输入虽然是3,但求的是5*5的幻方。 3. #include
using namespacestd; int n, s,a[100005], t[100005], i; void
mergesort(intl, int r){
if (l == r)
return;
int mid = (l + r) / 2;
int p = l;
int i = l;
int j = mid + 1;
mergesort (l, mid);
mergesort (mid + 1, r);
while (i <= mid && j<= r){
if (a[j] < a[i]){
s += mid – i+1;
t[p] = a[j]; p++; j++;
}
else {
t[p] = a[i];
p++; i++;
}
}
while (i <= mid){
t[p] = a[i];
p++;
i++;
}
while (j <= r){
t[p] = a[j];
p++;
j++;
}
for (i = l; i <= r; i++ )
a[i] = t[i]; } int main() { cin >> n; for (i = 1; i <= n;
i++) cin>> a[i]; mergesort (1, n);
cout << s << endl; return 0; } 输入: 6 2 6 3 4 5 1
输出: 8 解析:一眼看透本质:求逆序对。 然后就很容易的数出来了。
但是是怎么看出来本质的呢?
本题和上一题这样一眼看透本质,有两种方法:1、看算法,是自己熟悉的某个算法,那么恭喜你,你看透了本质。 4.
#include using namespacestd; int main() { int n, m; cin >> n
>> m; int x = 1; int y = 1; int dx = 1; int dy = 1; int cnt =
0; while (cnt != 2) { cnt = 0; x = x + dx; y = y + dy; if (x == 1
|| x == n) { ++cnt; dx = -dx; } if (y == 1 || y == m) { ++cnt; dy =
-dy; } } cout << x << " " << y<< endl;
return 0; } 输入1: 4 3 输出1: 1 3 (2 分) 输入2: 2017 1014
输出2: 2017 1 (3 分) 输入3: 987 321 输出3: 1
321 (3分) 解析:很明显第一个空是给我们模拟找规律的,其实模拟一下就能发现规律了,规律就是:
求出输入的两个数的最小公倍数 然后用最小公倍数分别除以两个输入的数 如果结果是单数,则输出的是输入的这个数本身
如果结果是偶数,则输出的是1 注意输出顺序 这样就能顺利地写出结果。
--end--
声明:本文章由网友投稿作为教育分享用途,如有侵权原作者可通过邮件及时和我们联系删除:freemanzk@qq.com