2019.7.29考试记录

7.29日考试记录

机房模考:2019.7.29

这套题应该算经典的吧不然为什么要考233

上面题目应该在各大OJ都可以找到。

而且本人以前应该做过233 那还考的这么差

题目难度整体不大,题量总共6道,但水分给得很足,切掉两题只要10分钟左右吧

所以来分析题目:


1. 1+1=?

源程序名 add.pas/add.cpp
输入文件名 add.in
输出文件名 add.out
时间限制 1s
空间限制 64MB

1+1=?
这个问题的答案可谓仁者见仁,智者见智。
如果在小学智力竞赛试卷上出现了 1+1=?的题目,有多少人会答 2呢?我不知道,而且
对于这道题目来说,这也不重要。
在这个题目中,你并不需要动歪脑筋,问你 1+1=? 你回答2 就可以了。

输入
仅一行,符合格式 A+B,0<=A,B<=60000(A,B 为整数)文件不含空格,数字开头无多余的
零。

输出
仅一行,即 A与B的和。

样例
add.in
113+355

add.out
468


题目看起来很水,然后…确实是真的很水/笑哭。就是一个非常非常简单的A+B problem。然后我们看看题解是怎么做的…

递归累加,LCT,树状数组,Splay,SPFA,Dijkstra,Floyd,压位高精,你值得拥有23333

好吧我看不下去了

Code:

#include
using namespace std;
int a,b;
int main(){
	freopen("add.in","r",stdin);
	freopen("add.out","w",stdout);
	scanf("%d+%d",&a,&b);
	printf("%d",a+b);
}

2. FIX

源程序名 fix.pas/fix.cpp
输入文件名 fix.in
输出文件名 fix.out
时间限制 1s
空间限制 64MB

如果单词X由单词 Y的前若干个字母构成,我们称X是 Y的前缀,例如“c”、“ca”、“cat”
是单词“cat”的前缀;类似地如果单词 X 由单词 Y 的最后若干个字母构成,我们称 X 是 Y
的后缀,例如“t”、“at”、“cat”是单词“cat”的后缀。请你编一程序判断一组单词是否
满足任一单词都不是其它单词的前缀且任一单词都不是其它单词的后缀。

输入
输入文件共有 3N+1行,其中第一行包含一个正整数N(N<=10),表示要你作出判断的单
词总组数,每组单词有三个。接下来的 3N 行每行一个单词,每个单词长度不超过255。

输出
输出文件共有 N行,每行输出一个“Yes”或“No”,表示对相应的三个单词给出的判断
结果,满足条件输出“Yes”,不满足条件输出“No”。

样例
fix.in
2
abba
aab
bab
a
ab
aa

fix.out
Yes
No


模拟大水题,其实本人看到此题差点就动手KMP了,一看数据,一手简单的字符串模拟/笑哭。简直让我想起了一道字符串模拟经典好题山东OI猪国杀,

完美的养生模拟好题,令人神清气爽,心旷神怡恨不得赶紧打完不想浪费生命。

直接贴吧写的好丑的

Code:

 
#include
using namespace std;
const int MAX_LONG=300;
int n,len[3];
char s[11][3][MAX_LONG];
int main(){
	freopen("fix.in","r",stdin);
	freopen("fix.out","w",stdout);
	scanf("%d",&n);
	for(int o=0;o<n;o++){
		for(int i=0;i<3;i++)
			scanf("%s",s[o][i]),len[i]=strlen(s[o][i]);
		bool flag=0,ok1=0,ok2=0;;
		for(int i=0;i<2;i++){ 
			for(int j=i+1;j<3;j++){
				ok1=0,ok2=0;
				int lenm=min(len[i],len[j]);
				for(int k=0;k<lenm;k++){
					if(s[o][i][k]!=s[o][j][k]) ok1=1;
					if(s[o][i][len[i]-1-k]!=s[o][j][len[j]-1-k]) ok2=1;
					if(ok1 && ok2) break;
				}
				if(!ok1 || !ok2) {
					printf("No\n");
					flag=1;
					break;
				}
			}
			if(!ok1 || !ok2) break;
		}
		if(!flag) printf("Yes\n");
	}
	return 0;
}

3.零件分组

源程序名 stick.pas/stick.cpp
输入文件名 stick.in
输出文件名 stick.out
时间限制 1s
空间限制 64MB

某工厂生产一批棍状零件,每个零件都有一定的长 Li)和重量(Wi)。现在为了加
工需要,要将它们分成若干组,使每一组的零件都能排成一个长度和重量都不下降(若 i 则Li<=Lj,Wi<=Wj)的序列。请问至少要分成几组?

输入
第一行为一个整数 N(N<=1000),表示零件的个数。第二行有 N对正整数,每对正整数
表示这些零件的长度和重量,长度和重量均不超过10000。

输出
仅一行,即最少分成的组数。

样例
stick.in
5
8 4 3 8 2 3 9 7 3 5

stick.out
2


经典的贪心题。通过可以联想到导弹拦截这道题。其实也差不多。

简单说说,由于这个是一个二维的不下降序列,所以可以先按照一个关键字排序一波。

接着再按照另一个关键字不降序贪心,能放就放就能A掉本题。

那为什么满足贪心选择呢?

本人也难以给出严谨证明,只能通过一些数据给出一些…扯淡的简单的描述吧…

比如样例(按长度排序)
2 3
3 5
3 8
8 4
9 7
中,先处理了(2,3)这个零件,因为还没有开组,所以毫无疑问的先开下一个组放下零件,于是我们就有了第一组,用零结尾
2 0
0
然后放3,很明显,一个组的长度限制越小越优,所以
2 3 0 (长度限制为3)
0 (长度限制为0)
优于
2 0 (长度限制为2)
3 0 (长度限制为3)
也就易得贪心的正确性了。

其实本题还有一个做法,那就是通过某关键词排序后再寻找另一个关键词的最长下降子序列(长度即为答案),也给出一个小小的证明:

在贪心中,我们能贪出一个不下降子序列就将其分出一组。也就是当它下降时就不能放到一组而是需要重开。就是说有多长的下降子序列就开多少个组嘛。所以跑一手dp找最长下降子序列就ojbk了啦

Code(贪心):

#include
using namespace std;
const int MAXN=1005;
int n,ans;
bool flag[MAXN];
struct node{
	int w,l;
}q[MAXN];
bool cmp(node x,node y){
	if(x.l!=y.l)return x.l<y.l;
	else return x.w<y.w;
}
int main(){
	freopen("stick.in","r",stdin);
	freopen("stick.out","w",stdout);
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d%d",&q[i].l,&q[i].w);
	sort(q,q+n,cmp);
	for(int i=0;i<n;i++){
		int wei=-INT_MAX,len=-INT_MAX;
		if(flag[i]) continue;ans++;
		for(int j=i;j<n;j++){
			if(q[j].w>=wei && q[j].l>=len){
				if(flag[j]) continue;
				else {
					flag[j]=1;
					wei=q[j].w;
					len=q[j].l;
				}
			}
		} 
	}
	printf("%d",ans);
	return 0;
}

4. 网球俱乐部

源程序名 tennis.pas/tennis.cpp
输入文件名 tennis.in
输出文件名 tennis.out
时间限制 1s
空间限制 64MB

俱乐部为了吸引更多的会员,决定邀请一些明星打表演赛。每个明星都表示他们只想打
一定数量场次的比赛。你的任务是安排比赛场次,满足每个明星的愿望,并且要保证,两个
人之间只能打一场比赛。

输入
文件TENNIS.IN第一行是整数N(2 N 1000),接下来的 N行每行表示该明星要
打的比赛场次G (1 G < N)。明星依次用整数 1到 N来表示。
i i

输出
输出到文件TENNIS.OUT。如果这样的计划不存在,输出NO SCHEDULE。否则输出SCHEDULE。
如果计划存在,接下来的 N 行,每行分别输出该明星的对手。对手必须按照升序输出。
如果有多种方案,任意一种即可。

样例
tennis.in
3
1
2
1
tennis.out
SCHEDULE
2
1 3
2
tennis.in
3
2
2
1
tennis.out
NO SCHEDULE


也是贪心2333333。策略就是每次将需要比赛次数最多的和次多,再次多一个一个比赛(简单来说,如果在能打完的情况下,最大的肯定要跟更多人打(废话),而在最后次数不多的时候处理大数可能处理不完233,所以先处理大的)。

主要就是判定每两个人不能打两次,最后输出要按升序等等

贴上没有半点借鉴价值(考试出了状况所以写的很丑没有优化)的代码
Code:

#include
using namespace std;
const int MAXN=1005;
int n,g,sum;
struct node{
	int num,g;
}q[MAXN];
bool cmp(node x,node y){
	return x.g>y.g;
}
bool flag[MAXN][MAXN],fl;
priority_queue <int,vector<int>,greater<int> > ds[MAXN];
int main(){
	freopen("tennis.in","r",stdin);
	freopen("tennis.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&q[i].g),q[i].num=i;
	sort(q+1,q+n+1,cmp); 
	while(q[1].g!=0 && q[2].g!=0 && !fl){
		fl=1;
		for(int j=2;j<=n && q[1].g>0 && q[j].g>0;j++){
			if(flag[q[1].num][q[j].num]) continue;
			flag[q[1].num][q[j].num]=flag[q[j].num][q[1].num]=1;
			fl=0,q[1].g--;q[j].g--;
			ds[q[1].num].push(q[j].num);
			ds[q[j].num].push(q[1].num);
		}
		sort(q+1,q+n+1,cmp);
	}
	sort(q+1,q+n+1,cmp);
	if(q[1].g!=0){
		printf("NO SCHEDULE\n");
		return 0;
	}
	printf("SCHEDULE\n");
	for(int i=1;i<=n;i++){
		while(!ds[i].empty()) {
			int tmp=ds[i].top();ds[i].pop();
			printf("%d ",tmp);
		}
		printf("\n");
	}
	return 0;
}



5.POWER

源程序名 power.pas/power.cpp
输入文件名 power.in
输出文件名 power.out
时间限制 1s
内存限制 128M

FJ的奶牛想要快速计算整数 P的幂 (1 <= P <=20,000),它们需要你的帮助。因为计算
极大数的幂,所以它们同一时间仅能使用 2 个存储器,每个存储器可记录某个结果值。
第一件工作是初始化存储器内的值一个为底数 x, 另一个为 1。 奶牛可以相乘或相除
2个存储器中的值,并把结果存在其中某个存储器内,但所有存储的结果必须是整数。
例如, 如果他们想计算 x^31, 一种计算方法是:
WV1 WV2
开始: x 1
存储器1和存储器 1相乘,结果存于存储器 2: x x^2
存储器2和存储器 2相乘,结果存于存储器 2: x x^4
存储器2和存储器2相乘,结果存于存储器 2: x x^8
存储器2和存储器 2相乘,结果存于存储器 2: x x^16
存储器2和存储器 2相乘,结果存于存储器 2: x x^32
存储器2和存储器 1相除,结果存于存储器 2: x x^31
因此, x^31可以通过 6次计算得出。给出要计算的幂次,要求求出最少需要几次计算。

输入
仅一个整数: P。

输出
仅一个整数:最少计算次数。

样例
power.in
31
power.in
6


这题…考场上面打了一手次方的大暴力,没有冷静分析一波。但是其实题目真的不难怎么又是这句话

题目确实是一手大搜索,但是首先用广搜将快的多,那么,广搜怎么存状态呢?

很难存。数据范围并不允许我们开一手二维的状态保存数组。所以应该想到的是跑一手迭代加深虽然我没想到

一层层搜,时间的话比广搜稍微慢一点,但是胜在无需空间。

层数最多差不多是log2( P ),大概12,13的样子,所以最后一层差不多是8^12次方。所以可能会超。。。于是就需要玄学剪枝一波。

首先,当容器内的指数的最大公约数不是P的约数时,可以剪枝。因为很明显的是,这种情况下,只能够构造出两个容器内指数的最大公约数的倍数的指数(仔细思考吧233)。还有就是即使将剩余层数全部用于倍增都无法超越(达到)P,则无论如何都跑不到P了,剪枝。这样可以让时间更加接近广搜一点。两个剪枝完全够用,而且跑的挺快2333,代码奉上
Code:

#include
using namespace std;
int n,k;
bool DFS(int x,int u,int v){
    if(x>k)return 0;
    if(u>v)u^=v^=u^=v;
    if((v<<(k-x))<n)return 0;
    if(n%__gcd(u,v))return 0;
    if(u==v)return 0;
    if(v==n)return 1;
    if(DFS(x+1,u+v,v))return 1;
    if(DFS(x+1,v+v,v))return 1;
    if(DFS(x+1,u+u,v))return 1;
    if(DFS(x+1,v-u,v))return 1;
    if(DFS(x+1,u,u+v))return 1;
    if(DFS(x+1,u,v-u))return 1;
    if(DFS(x+1,u,u+u))return 1;
    if(DFS(x+1,u,v+v))return 1;
    return 0;
}
int main(){	
	freopen("power.in","r",stdin);
	freopen("power.out","w",stdout);
    scanf("%d",&n);
    while(!DFS(0,0,1))k++;
    printf("%d",k);
}


6. MQUEUE

源程序名 mqueue.pas/c/cpp
输入文件名 mqueue.in
输出文件名 mqueue.out
时间限制 1s
内存限制 64MB

每天早晨,Farmer John 的 N(1<=N<=25,000)头奶牛都排成一列,逐一接受挤奶。为了
提高挤奶的 FJ 把整个挤奶过程划分成两道工序,每头牛都得连续地完成这些挤奶工
序。奶牛们一个接一个地进入挤奶的牛棚,FJ 负责实行第一道工序,第二道工序则让他的
好友 Farmer Rob 帮助完成。并且,如果某头奶牛先于另一头奶牛开始进行第一道工序,那
么她开始第二道工序的时间也一定在那一头奶牛之前。
Farmer John发现,如果奶牛们按某种顺序排队进行挤奶,那么可能会在排队等待上
花很多的时间。比方说,如果 Farmer John 要花很长时间才能完成某头奶牛挤奶时的第一
工序,那么Farmer Rob可能会有一段时间没有事做。当然,如果FJ的工作完成得太快,Farmer
Rob面前就会有很多奶牛排起长队。
请你帮助Farmer John计算一下,如果按照最优的排队方式,最少需要多少时间才能把
所有奶牛都挤过奶。对于每头奶牛,我们都知道在她身上完成第一道工序所需的时间 A(i),
以及完成第二道工序的时间 B(i)。A(i)和 B(i)的范围都在1…20,000之间。

输入
第1行: 一个整数 N
第2…1+N行: 第i+1包括2个用空格隔开的整数,表示第i头牛的A(i)和B(i)值

输出
第1行: 输出按照最优方案排队后,最少需要多少时间才能完成对所有奶牛的挤奶

样例
mqueue.in
3
2 2
7 4
3 5

mqueue.out
16

样例说明
一共有 3头奶牛。1 号奶牛完成每道工序都需要 2 单位时间,2 号奶牛完成两道工序分
别需要7个和4个单位时间,3号奶牛完成两道工序所需时间为3个单位和5个单位。
把奶牛们按照 3,1,2的顺序排队,这样挤奶总共花费16个单位时间。


这道题…其实不难。在我们机房的主流写法是用一个奇怪的排序规则去排序然后贪心。但是本人觉得其实没那么麻烦233。

由于我并没有仔细思考那个排序规则,所以就只讲讲自己思路

很明显,我们要让两个人的空闲时间尽量小。所以先选出一列A<=B的奶牛(即A工序的时间小于B工序的时间),并在其中选出A工序最小的奶牛。这样就可以保证在处理完最小的奶牛之后B工序不会空闲,并且B等第一只奶牛的时间是最短的。再分为B

第一种情况,B工序的总时间加上第一头奶牛大于A工序的总时间。此时在A完成后,B仍然还在工作没有空闲,此时时间便是B工序的时间加上等待时间。

第二种情况,A工序的总时间大于了B的时间,此时B将会断断续续地出现空闲情况,但最后一头奶牛总是要在A最后一头结束后才能开始处理,所以此时应该把最后一头奶牛设置为B工序最小的奶牛(在A>B序列中),总时间为A工序时间加上A等待时间(最后一头奶牛)

所以得到答案便是MAX(Sum(集合(A<=B))+Min(集合(A>B))的B处理时间),Sum(集合(A>B))+Min(集合(A<=B))的A处理时间))

看不懂?没关系,代码清晰很多

Code:

#include
using namespace std;
const int MAXN=25005;
int n,tmp1,tmp2,i1,i2,sum1,sum2;
struct node{
	int a,b;
}q1[MAXN],q2[MAXN];
bool cmp1(node x,node y){
	if(x.a!=y.a)return x.a<y.a;
	else return y.b>x.b;
}
bool cmp2(node x,node y){
	if(x.a!=y.a)return x.b>y.b;
	else return y.a<x.a;
}
int main(){
	freopen("mqueue.in","r",stdin);
	freopen("mqueue.out","w",stdout);
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d%d",&tmp1,&tmp2);
		if(tmp1<=tmp2) q1[i1].a=tmp1,q1[i1++].b=tmp2;
		if(tmp1>tmp2) q2[i2].a=tmp1,q2[i2++].b=tmp2;
	}
	sort(q1,q1+i1,cmp1);
	sort(q2,q2+i2,cmp2);
	for(int i=0;i<i1;i++) sum1+=q1[i].a;
	for(int i=0;i<i2;i++) sum1+=q2[i].a;
	for(int i=0;i<i1;i++) sum2+=q1[i].b;
	for(int i=0;i<i2;i++) sum2+=q2[i].b;
	sum2+=q1[0].a;
	sum1+=q2[i2-1].b;
	printf("%d",max(sum1,sum2));
	return 0;
}

总而言之,考试需冷静,其实这次得分完全可以高个100左右(虽然还是不高233),存在很多跑挂了的情况,有一个原因就是考试时电脑重启影响了心态。细细想想,其实在NOIP2018里面我也是犯了这个毛病,延长(特殊情况)的时间里一个暴力都没打出,直接浪费了40分钟+。虽然不会再怨天尤人,但是内心难免急躁。静心为主吧

你可能感兴趣的:(笔记)