前言
因为NOIP原题各大OJ上都是有的,本博客不再重复粘贴题目的工作,只写下题解和AC程序。
第一题 数的计算
递归写即可。
第二题 最大公约数和最小公倍数
设p1 = p / x0, q1 = q / x0。因为x0是最大公约数,所以p1,q1互质。又因为y0 = pq / x0。有p1q1 = y0 / x0。
设s = y0 / x0。即求p1q1 = s且p1,q1互质的解数。
将s分解质因数。因为p1,q1互质,所以两数不会有相同的质因数。那么p1,q1的解数就是s的质因数个数k的2的幂。
即ans = 2 ^ k。
第三题 求先序排列
设a是中序遍历,b是后序遍历。a[l]…a[r]对应b[x]…b[y]。那么b[y]是这颗子树的根节点,将其输出。设a[i] = b[y](l <= i <= r)。那么左子树的节点个数是i – l – 1。b[x]中从x开始i – l - 1长度的是左子树的后续遍历。a[l]…a[i]是左子树的中序遍历。b[x]中除去左子树后根节点的那段是右子树。a[x]中a[i + 1]…a[r]是右子树。分别递归处理。
第四题 装箱问题
01背包。详见《背包九讲》。
代码
第一题
#include <stdio.h>
int n,ans;
void find(int x) {
for (int i = 1;i <= x / 2;++i) {
++ans;
find(i);
}
}
int main() {
scanf("%d",&n);
ans = 1;
find(n);
printf("%d\n",ans);
return 0;
}
第二题
#include <stdio.h>
long long p,t,x,y,ans,k;
int main() {
scanf("%lld%lld",&x,&y);
if (y % x) {
printf("0\n");
return 0;
}
p = y / x;
t = 2;
while (p > 1) {
if (p % t == 0) {
++k;
while (p % t == 0)
p /= t;
}
++t;
}
ans = 2;
for (int i = 1;i < k;++i)
ans *= 2;
printf("%lld\n",ans);
return 0;
}
第三题
#include <stdio.h>
#include <string.h>
#define MAXN 10
char a[MAXN],b[MAXN];
void find(int l,int r,int x,int y) {
if (l > r)
return;
printf("%c",b[y]);
if (l == r)
return;
for (int i = l;i <= r;++i)
if (a[i] == b[y]) {
find(l,i - 1,x,x + i - l - 1);
find(i + 1,r,x + i - l,y - 1);
return;
}
}
int main() {
scanf("%s%s",a,b);
int len = strlen(a);
find(0,len - 1,0,len - 1);
return 0;
}
第四题
#include <stdio.h>
#define MAXV 20010
int f[MAXV],v,w,n;
int main() {
scanf("%d%d",&v,&n);
for (int i = 1;i <= n;++i) {
scanf("%d",&w);
for (int j = v;j >= w;--j)
if (f[j] < f[j - w] + w)
f[j] = f[j - w] + w;
}
printf("%d\n",v - f[v]);
return 0;
}