2018-10-02NOIP提高组练习

第一题:


题目描述

R 国和 S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动。
历尽艰险后,潜伏于 S 国的 R 国间谍小 C 终于摸清了 S 国军用密码的编码规则:

    S 国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所得的内容均由大写字母 A−ZA-ZA−Z 构成(无空格等其他字符);
    S 国对于每个字母规定了对应的“密字”。加密的过程就是将原信息中的所有字母替换为其对应的“密字”;
    每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”。“密字”可以和原字母相同。

例如,若规定 A 的密字为 A, B 的密字为 C (其他字母及密字略),则原信息 ABA 被加密为 ACA 。

现在,小 C 通过内线掌握了 S 国网络上发送的一条加密信息及其对应的原信息。小 C 希望能通过这条信息,破译 S 国的军用密码。小 C 的破译过程是这样的:扫描原信息,对于原信息中的字母 xxx(代表任一大写字母),找到其在加密信息中的对应大写字母 yyy,并认为在密码里 yyy 是 xxx 的密字。如此进行下去直到停止于如下的某个状态:

    所有信息扫描完毕,A,B,...,Z 所有 262626 个字母在原信息中均出现过并获得了相应的“密字”;
    所有信息扫描完毕,但发现存在某个(或某些)字母在原信息中没有出现;
    扫描中发现掌握的信息里有明显的自相矛盾或错误(违反 S 国密码的编码规则)。例如某条信息 XYZ 被翻译为 ABA 就违反了“不同字母对应不同密字”的规则。

在小 C 忙得头昏脑涨之际,R 国司令部又发来电报,要求他翻译另外一条从 S 国刚刚截取到的加密信息。
现在请你帮助小 C:通过内线掌握的信息,尝试破译密码。然后利用破译的密码,翻译电报中的加密信息。
输入格式

共 333 行,每行为一个字符串。
第 111 行为小 C 掌握的一条加密信息。
第 222 行为第 111 行的加密信息所对应的原信息。
第 333 行为 R 国司令部要求小 C 翻译的加密信息。
输出格式

共 111 行。
若破译密码停止时出现 2,32, 32,3 两种情况,请你输出 Failed(注意首字母大写,其它小写)。
否则请输出利用密码翻译电报中加密信息后得到的原信息。
样例
样例输入 1

AA
AB
EOWIE

样例输出 1

Failed

样例说明 1

原信息中的字母 A 和 B 对应相同的密字,输出 Failed 。
样例输入 2

QWERTYUIOPLKJHGFDSAZXCVBN
ABCDEFGHIJKLMNOPQRSTUVWXY
DSLIEWO

样例输出 2

Failed

样例说明 2

字母 Z 在原信息中没有出现,输出 Failed 。
样例输入 3

MSRTZCJKPFLQYVAWBINXUEDGHOOILSMIJFRCOPPQCEUNYDUMPP
YIZSDWAHLNOVFUCERKJXQMGTBPPKOIYKANZWPLLVWMQJFGQYLL
FLSO

样例输入 3

NOIP

数据范围与提示

对于所有数据,保证所有字符串仅由英语大写字母构成,长度在 1 到 100 之间,且第 1 行长度与第 2 行相等。

分析:这一题就是一个模拟题,首先判断一下26个字母是否都在原文中,然后判断密文和原文之间的翻译是否重复或疏漏,以上两种情况直接输出“Failed”即可,其余情况就直接对照即可,但是我莫名RE了两个点23333:
代码:

#include<bits/stdc++.h>
using namespace std;
string a,b,c,d;
int noip=233333333;
int search(char n){
	int k=2333;
	for(int i=0;i<a.size();i++)
	    if(a[i]==n){
		   k=i;
		   break;
		}
	if(k==2333){
	   noip=-1;
	   return 23333;
	}
	else
	   return k;
}
bool pd(){
	for(char i='A';i<='Z';i++){
	    int flag=0;
	    for(int j=0;j<b.size();j++)
		    if(b[j]==i)
			   flag=1;
		if(flag==0)
		   return false;
	}
	for(int i=0;i<c.size();i++){
	    int flag=0;
	    for(int j=0;j<a.size();j++)
		    if(c[i]==a[j])
			   flag=1;
		if(flag==0)  
		   return false;
	}
	for(int i=0;i<a.size();i++){
		char k=b[i];
	    for(int j=i+1;j<b.size();j++)
		    if((b[j]==k&&a[j]!=a[i])||(b[j]!=k&&a[j]==a[i]))
			   return false;
	}
	return true;
}
int main(){
    cin>>a>>b>>c;
	string kkk;
	if(pd()==false){
		cout<<"Failed";
		return 0;
	}
	for(int i=0;i<c.size();i++){
	    int x=search(c[i]);
		noip=233333333;
	    if(x==23333||noip==-1){
		   cout<<"Failed";
		   return 0;
		}
		else
      		kkk[i]=b[x];
	}
	for(int i=0;i<c.size();i++)
	    cout<<kkk[i];
	return 0;
}

第二题:


题目描述

小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。

这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的查找和翻译。

假设内存中有 M 个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过 M−1 ,软件会将新单词存入一个未使用的内存单元;若内存中已存入 M 个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。

假设一篇英语文章的长度为 N个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。
输入格式

输入共 2 行。每行中两个数之间用一个空格隔开。

第一行为两个正整数 M 和 N,代表内存容量和文章的长度。

第二行为 N 个非负整数,按照文章的顺序,每个数(大小不超过 1,000)代表一个英文单词。文章中两个单词是同一个单词,当且仅当它们对应的非负整数相同。
输出格式

输出共 111 行,包含一个整数,为软件需要查词典的次数。
样例
样例输入 1

3 7
1 2 1 5 4 4 1

样例输出 1

5

样例 1 说明

整个查字典过程如下:每行表示一个单词的翻译,冒号前为本次翻译后的内存状况:

空:内存初始状态为空。

    1:查找单词 1 并调入内存;
    1 2:查找单词 2 并调入内存;
    1 2:在内存中找到单词 1 ;
    1 2 5:查找单词 5 并调入内存;
    2 5 4:查找单词 4 并调入内存替代单词 1;
    2 5 4:在内存中找到单词 4 ;
    5 4 1:查找单词 1 并调入内存替代单词 2;

共计查了 5 次词典。
样例输入 2

2 10
8 824 11 78 11 78 11 78 8 264

样例输出 2

6

数据范围与提示

对于 10% 的数据有 M=1,N≤5;

对于 100% 的数据有 0<M≤10000,0<N≤1,0000。

分析:这道题也是一个模拟题,可以用栈来做,但这里我用的是别的方法:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000+10;
char str[maxn];
int n,m,f,flag,ans,head,tail,inl[maxn];
int main(){
    cin>>m>>n;
    head=1;
	tail=0;
	ans=0;
    for(int i=1;i<=n;i++){
        cin>>f;
        flag=0;
        for(int j=head;j<=tail;j++)
            if(f==inl[j]&&flag==0){
              flag=1;
              break;
            } 
        if(flag==0){
            ans++;
            tail++;
            inl[tail]=f;
            while((tail-head+1)>m) 
              head++;
        }
    }
    cout<<ans;
    return 0;    
} 

第三题:

题目描述
为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。
一共有 nnn 张地毯,编号从 111 到 nnn 。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。
地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。
注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

输入格式
输入共 n+2n+2n+2 行。
第一行,一个整数 nnn,表示总共有 nnn 张地毯。
接下来的 nnn 行中,第 i+1i+1i+1 行表示编号 iii 的地毯的信息,包含四个正整数 a,b,g,k ,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标 (a,b)(a,b)(a,b) 以及地毯在 xxx 轴和 yyy 轴方向的长度。
第 n+2n+2n+2 行包含两个正整数 xxx 和 yyy ,表示所求的地面的点的坐标 (x,y)(x,y)(x,y) 。

输出格式
输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出 −1-1−1 。


样例
样例输入 1
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2
样例输出 1
3
样例说明 1
如下图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,覆盖点(2, 2)的最上面一张地毯是 3 号地毯。

样例输入 2
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5
样例输出 2
-1
样例说明 2
如上图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,点(4,5) 没有被地毯覆盖,所以输出-1。

数据范围与提示
对于 30% 的数据,有 n≤2;
对于 50% 的数据,a,b,g,k≤100;
对于 100%的数据,有 0≤n≤10,0000,0≤a,b,g,k≤100,0000 。

分析:这道题可以跟树联系上
代码:

#include <bits/stdc++.h> 
using namespace std;
const int maxn=100000+100;
int a[maxn],b[maxn],c[maxn],d[maxn],n,x,y;
int main(){
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i]>>b[i]>>c[i]>>d[i];
    cin>>x>>y;
    for(int i=n;i>=0;i--){
        if(a[i]>x||b[i]>y)
           continue;
        if(a[i]+c[i]<x||b[i]+d[i]<y)
           continue;
        cout<<i+1;
        return 0;
    }
    cout<<-1;
    return 0;
}

第四题:


题目描述

NOIP 复赛之前,HSD 桑进行了一项研究,发现人某条染色体上的一段 DNA 序列中连续的 kkk 个碱基组成的碱基序列与做题的 AC 率有关!于是他想研究一下这种关系。
现在给出一段 DNA 序列,请帮他求出这段 DNA 序列中所有连续 kkk 个碱基形成的碱基序列中,出现最多的一种的出现次数。
输入格式

两行,第一行为一段 DNA 序列,保证 DNA 序列合法,即只含有 A, G, C, T 四种碱基;
第二行为一个正整数 kkk,意义与题目描述相同。
输出格式

一行,一个正整数,为题目描述中所求答案。
样例
样例输入 1

AAAAA
1

样例输出 1

5

样例解释 1

对于这段 DNA 序列,连续的 1 个碱基组成的碱基序列只有 A,共出现 5 次,所以答案为 5。
样例输入 2

ACTCACTC
4

样例输出 2

2

样例解释 2

对于这段 DNA 序列,连续的 444 个碱基组成的碱基序列为:ACTC, CTCA, TCAC 与 CACT。其中 ACTC 出现 2 次,其余均出现 1 次,所以出现最多的次数为 2,即为答案。
数据范围与提示

记 DNA 序列长度为 nnn。
本题共 10 组数据,只有输出与标准输出一致才可以获得该测试点的分数。

性质:给出的 DNA 碱基序列中每个碱基均相同。
对于所有数据均保证 k≤n

分析:桶排即可
代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=10000000+10;
string a;
int b[maxn];
int n,maxx,ans;
int main(){
	cin>>a;
	scanf("%d",&n);
	int len;
	for(int i=0;i<=a.size()-n;i++){
	    int len=0;
	    for(int j=i;j<i+n;j++){
		    if(a[j]=='A')
			   len*=4;
			if(a[j]=='G')
			   len=len*4+1;
			if(a[j]=='C')
			   len=len*4+2;
			if(a[j]=='T')
			   len=len*4+3;
		}
		b[len]++;
	}
	for(int i=0;i<=10000000;i++)
	    maxx=max(maxx,b[i]);
	cout<<maxx;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值