NOIP2006解题报告PJ

NOIP2006解题报告PJ
                             by MPS
------------------------------------------------------------------------------------------------------------------------------------------------------------
1.明明的随机数
(random.pas/c/cpp)
【问题描述】
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先
用计算机生成了 N 个 1 到 1000 之间的随机整数(N≤100),对于其中重复的
数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。
然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明
完成“去重”与“排序”的工作。
【输入文件】
输入文件 random.in 有 2 行,第 1 行为 1 个正整数,表示所生成的随机数
的个数:
N
第 2 行有 N 个用空格隔开的正整数,为所产生的随机数。
【输出文件】
输出文件 random.out 也是 2 行,第 1 行为 1 个正整数 M,表示不相同的随
机数的个数。第 2 行为 M 个用空格隔开的正整数,为从小到大排好序的不相同
的随机数。
【输入样例】
10
20 40 32 67 40 20 89 300 400 15
【输出样例】
8
15 20 32 40 67 89 300 400

【分析】
暴力桶排秒过。。。第一题永远都。。
#include <iostream>
using namespace std;
#include <cstdio>

const int MaxN=1001;

int t[MaxN],n,x,l=0,i;

int main(){
   freopen("random.in","r",stdin);
   freopen("random.out","w",stdout);
   cin>>n;
   for(i=1;i<=n;i++){
   	cin>>x;
   	if(t[x]==0)l++;
   	t[x]++;
   }
   cout<<l<<endl;
   for(i=1;i<MaxN;i++)
      if(t[i])cout<<i<<" ";
   return 0;
}

//没什么好讲的,标准算法:桶排 

2.开心的金明
(happy.pas/c/cpp)
【问题描述】
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用
的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些
物品,怎么布置,你说了算,只要不超过 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]。(其中*为乘号)
请你帮助金明设计一个满足要求的购物单。
【输入文件】
输入文件 happy.in 的第 1 行,为两个正整数,用一个空格隔开:
N m
(其中 N(<30000)表示总钱数,m(<25)为希望购买物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有
2 个非负整数
v p
(其中 v 表示该物品的价格(v<=10000),p 表示该物品的重要度(1~5))
【输出文件】
输出文件 happy.out 只有一个正整数,为不超过总钱数的物品的价格与重要
度乘积的总和的最大值(<100000000)。
【输入样例】
1000 5
800 2
400 5
300 5
400 3
200 2
【输出样例】
3900

【分析】
详细在code里
【code】
#include <iostream>
using namespace std;
#include <cstdio>

const int MaxN=30001;

int f[MaxN],n,w[MaxN],v[MaxN],i,j,m;

int main(){
   freopen("happy.in","r",stdin);
   freopen("happy.out","w",stdout);
   cin>>m>>n;
   for(i=1;i<=n;i++)cin>>w[i]>>v[i];
   for(i=1;i<=n;i++)
     for(j=m;j>=w[i];j--)
       f[j]=max(f[j],f[j-w[i]]+w[i]*v[i]);
   cout<<f[m];
   return 0;
}
/*标准算法:背包型动态规划
  阶段:金明的每次选择
  状态:f(i,j)表示选择前i件物品放入容量为j的背包所得最大价值
  转移方程f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+w[i]*v[i])
  时间复杂度O(NM)
  空间复杂度O(NM)->[优化一维]O(M) 
*/

3.Jam的计数法
(count.pas/c/cpp)
【问题描述】
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< span>,且不存在 Jam 数字 P,使 U<P<V< span>)。
你的任务是:对于从文件读入的一个 Jam 数字,按顺序输出紧接在后面的 5 个
Jam 数字,如果后面没有那么多 Jam 数字,那么有几个就输出几个。
【输入文件】
输入文件 counting.in 有 2 行,第 1 行为 3 个正整数,用一个空格隔开:
s t w
(其中 s 为所使用的最小的字母的序号,t 为所使用的最大的字母的序号。w
为数字的位数,这 3 个数满足:1≤s<T< span>≤26, 2≤w≤t-s )
第 2 行为具有 w 个小写字母的字符串,为一个符合要求的 Jam 数字。
所给的数据都是正确的,不必验证。
【输出文件】
输出文件 counting.out 最多为 5 行, 为紧接在输入的 Jam 数字
个 Jam 数字,如果后面没有那么多 Jam 数字,那么有几个就输出几个。
输出一个 Jam 数字,是由 w 个小写字母组成的字符串,不要有多余的空
【输入样例】
2 10 5
bdfij
【输出样例】
bdghi
bdghj
bdgij
bdhij
befgh

【分析】
我的算法:模拟+DFS
思路:对于修改字符串,就是模拟,对于一个位置上字符串的取值,为DFS
这样做的时间复杂度O(MN^3),期望得分:80分
显然,这样是会TLE的,那么我们怎么修改该呢?对了,DFS可以剪枝啊!我们不用来判断是否有序化,我们在生成的时候就可以选择了,这样时间复杂度降为O(N^3)
期望得分:100分
【code】
#include <iostream>
using namespace std;
#include <cstdio>
#include <string>

string a,last;
int s,t,n,k,m;
char c[101];

void init(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    cin>>s>>t>>n;
    for(k=1;k<=t-s+1;k++)c[k]=(char)(s+k-2+97);//creat the sequence
    cin>>a;
}

void out(){
    int i;
    if(m==5)return;
    if(a==last)return;
    for(i=1;i<n;i++)
      if(a[i]<=a[i-1])return;
    for(i=0;i<n;i++)
      cout<<a[i];
    last=a;m++;
    cout<<endl;
}

void dfs(int g,char z){
    if(g==n+1){out();return;}
    for(char i=z;i<=c[t-s+1];i++){
        char e=a[g];
        a[g]=i;
        dfs(g+1,i);//这里的i起到了剪枝的作用,原句会TLE↓
                   //dfs(g+1,z) 
        a[g]=e;
    }
}

void work(){
    int i,j;
    last=a;
    for(i=a.size()-1;i>=0;i--)
    {
        if(m==5)break;
        for(j=i+1;j<a.size();j++)
          if((char)(a[i]+(j-i))>c[t-s+1])break;
        if(j==a.size())//No problem
          dfs(i,a[i]+1);
    }
}

int main(){
    init();
    work();
    return 0;
}

4.数列
(sequence.pas/c/cpp)
【问题描述】
给定一个正整数k(3≤k≤15),把所有k的方幂及所有有限个互不相等的k
的方幂之和构成一个递增的序列,例如,当 k=3 时,这个序列是:
1,3,4,9,10,12,13,…
给你k,n,求第N项
【输入文件】
输入文件 sequence.in 只有 1 行,为 2 个正整数,用一个空格隔开:
k N
(k、N 的含义与上述的问题描述一致,且 3≤k≤15,10≤N≤1000)。
【输出文件】
输出文件 sequence.out 为计算结果,是一个正整数(在所有的测试数据
中,结果均不超过 2.1*10^9)
。(整数前不要有空格和其他符号)。
【输入样例】
3 100
【输出样例】
981

【分析】
直接看题目是找不出规律的,我们将n转换成2进制试试看?
(100)2=1100100
对应的:1*3^6+1*3^5+0*3^4+0*3^3+1*3^2+0*3^1+0*3^0
所以转换一下即可
【code】
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
     freopen("sequence.in","r",stdin);
     freopen("sequence.out","w",stdout);
     int k,m,x,sum=0,t=1;
     cin>>k>>m;
     while(m)
     {
         x=m&1;
         if(x) sum+=t;
         t*=k;
         m=m>>1;
     }
     cout<<sum;
     return 0;
}

总结:第4题想出来略费时间,其余都是水题,寻常得分350以上
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值