2006年NOIP普及组复赛真题解析

文章讲述了四个NOIP普及组题目,涉及随机数处理、去重、排序算法(如桶排序、动态规划),以及数学模型(如背包问题)。展示了如何使用C++实现这些技术解决实际问题。
摘要由CSDN通过智能技术生成

2006年NOIP普及组T1- 明明的随机数

题目描述

明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。

输入格式

输入文件random.in 有2行

第1行为1个正整数,表示所生成的随机数的个数:N

第2行有N个用空格隔开的正整数,为所产生的随机数。

输出格式

输出文件random.out 也是2行

第1行为1个正整数M,表示不相同的随机数的个数

第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

输入输出样例

输入样例1:
10
20 40 32 67 40 20 89 300 400 15
输出样例1:
 8
 15 20 32 40 67 89 300 400

时间限制1.00s   内存限制125.00MB

解析

考点:桶排序去重,set

#include<bits/stdc++.h>
using namespace std;
int n,t,a[1001],cnt;
int main() {	
	cin>>n;
	for(int i=1;i<=n;i++){
	    cin>>t;
	    a[t]=1;
	}
	for(int i=1;i<=1000;i++){
	   if(a[i]!=0) cnt++;
	}
	cout<<cnt<<endl;
	for(int i=1;i<=1000;i++){
	   if(a[i]!=0) cout<<i<<" ";//去重
	}
	return 0;
}

set集合

#include<bits/stdc++.h>
using namespace std;
int n,a[10001],cnt;
int main(){
	cin>>n;
	for(int i=0;i<n;i++)	cin>>a[i];
	set<int>s(a,a+n);
	set<int>::iterator it;
	for(it=s.begin();it!=s.end();it++)cnt++;
	cout<<cnt<<endl;
	for(it=s.begin();it!=s.end();it++)cout<<*it<<" ";
	return 0;
}

2006年NOIP普及组T2- 开心的金明

题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。于是,他把每件物品 规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:

v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*为乘号)

请你帮助金明设计一个满足要求的购物单。

输入格式

第1行,为两个正整数,用一个空格隔开:N m(其中N(<30000)表示总钱数,m(<25)为希望购买物品的个数。)

从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v p(其中v表示该物品的价格(v<=10000),p表示该物品的重要度(1~5))

输出格式

输出只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。

输入输出样例

输入样例1:
1000 5
800 2
400 5
300 5
400 3
200 2
输出样例1:
3900

时间限制1.00s   内存限制125.00MB

解析

考点:动态规划,背包

状态表示: f[i][j] 表示前i个物品在花费j元是的最大值 
状态 转移方程 就是基于之前的状态+当前的决策 ,获取当前状态 f[i]
状态计算:
    不选第i个物品  f[i][j]=f[i-1][j] 
    选第i个物品   f[i][j]=f[i-1][j-v[i]] +v[i]*w[i];
    f[i]=max( f[i-1],f[i-2]+a[i])

参考代码

#include<iostream>

using namespace std;
const int N=30005;
const int M=30;
int n,m;
int f[M][N],v[M],w[M];  //价格 重要度 
int main(){
	cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=m;i++){
    	for(int j=0;j<=n;j++){
    		//不选 
    		f[i][j]=f[i-1][j];
    		if(j>=v[i]){
    			f[i][j]=max(f[i][j],f[i-1][j-v[i]]+v[i]*w[i]);
			}
		}
	}
    cout<<f[m][n]; 		
    
	return 0;
}

一维

#include<iostream>
using namespace std;
const int N=3005;
int n,m;
int f[N],v[N],w[N];  //价格 重要度 
int main(){
	cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=m;i++)
    	for(int j=n;j>=v[i];j--) //倒序更新 
    		f[j]=max(f[j],f[j-v[i]]+v[i]*w[i]);
    cout<<f[n];
    return 0;
}

2006年NOIP普及组T3- Jam的计数法

题目描述

Jam是个喜欢标新立异的科学怪人。他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩。在他的计数法中,每个数字的位数都是相同的(使用相同个数的字母),英文字母按原先的顺序,排在前面的字母小于排在它后面的字母。我们把这样的“数字”称为Jam数字。在Jam数字中,每个字母互不相同,而且从左到右是严格递增的。每次,Jam还指定使用字母的范围,例如,从2到10,表示只能使用{b,c,d,e,f,g,h,i,j}这些字母。如果再规定位数为5,那么,紧接在Jam数字“bdfij”之后的数字应该是“bdghi”。(如果我们用U、V依次表示Jam数字“bdfij”与“bdghi”,则U<V,且不存在Jam数字P,使U<P<V)。

你的任务是:对于从文件读入的一个Jam数字,按顺序输出紧接在后面的5个Jam数字,如果后面没有那么多Jam数字,那么有几个就输出几个。

输入格式

输入文件counting.in 有2行

第1行为3个正整数,用一个空格隔开:s t w(其中s为所使用的最小的字母的序号,t为所使用的最大的字母的序号。w为数字的位数,这3个数满足:1≤s<T≤26, 2≤w≤t-s ) 

第2行为具有w个小写字母的字符串,为一个符合要求的Jam数字。所给的数据都是正确的,不必验证。

输出格式

输出文件counting.out 最多为5行,为紧接在输入的Jam数字后面的5个Jam数字,如果后面没有那么多Jam数字,那么有几个就输出几个。每行只输出一个Jam数字,是由w个小写字母组成的字符串,不要有多余的空格。

输入输出样例

输入样例1:
 2 10 5
 bdfij
输出样例1:
bdghi
bdghj
bdgij
bdhij
befgh

时间限制1.00s   内存限制125.00MB

解析

考点:字符串,数学,数论

参考代码:

#include <bits/stdc++.h>
using namespace std;
int s,t,w;
string jam;
int main(){
    cin>>s>>t>>w>>jam;
    for (int i=1;i<=5;i++)
      for (int j=w-1;j;j--)
        if (jam[j]-96<=j-w+t) {//判断这一位能不能增加
            jam[j]++;//这一位自加1
            for (int k=j+1;k<w;k++) jam[k]=jam[k-1]+1;//这一位之后的所有位也要加1
            cout<<jam<<endl;//找到就输出
            break;
        }
    return 0;
}

2006年NOIP普及组T4-数列

问题描述

给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k=3时,这个序列是:
1,3,4,9,10,12,13,…
(该序列实际上就是:3^0,3^1,3^0+3^1,3^2,3^0+3^2,3^1+3^2,3^0+3^1+3^2,…)
请你求出这个序列的第N项的值(用10进制数表示)。

例如,对于k=3,N=100,正确答案应该是981。

输入格式

两个由空格隔开的正整数 k, N(3≤k≤15,10≤N≤1000)。

输出格式

一个正整数。整数前不要有空格和其他符号。

输入输出样例

输入 #1

3 100

输出 #1

981
时间限制1.00s   内存限制125.00MB

解析

考点:进制转换

先把k转成二进制,再把二进制的每一位转成n进制

参考代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1001;
int a[N],n,k,l=0;
int main(){
    LL ans=0;
    scanf("%d%d",&n,&k);
    while(k)a[++l]=k%2,k/=2;//先转二进制
    for(int i=l;i>=1;i--)
        ans+=pow(n,i-1)*a[i];//再转n进制
    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值