校赛总结【hpu】失败的历程...

博主参加了11.29日的校赛,尽管题目简单,但因粗心和僵化的思维方式,仅获得二等奖。文章回顾了比赛中遇到的问题,包括基本输入输出、循环数组、素数判断、贪心算法等,指出部分题目出题质量不高,对比赛结果表示遗憾,并分享了解题思路和经验教训。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前天,11.29日,进行了一场校赛,比赛在自己学校的oj 进行的,然后很简单的题,基本上不考算法,结果自己却阴沟里翻船了..........只得了二等奖,而且差一点滑出银牌区,

个人认为自己不应该这么差啊,至少也要是金银交界处的,结果事实太残酷了.........


大致总结一下:

首先是自己太粗心,有好几个地方都没注意,除了很多不应该的差错.......

其次自己脑子太僵化了,失去了以前的灵活度,难道是学的东西太多了,智商不够用了?

最后,不得不吐槽一下出题的质量...........简直这就不应该是ACM比赛,直接改成 脑筋急转弯 大赛吧......算法题几乎没有,有了还是让一般人不会做的.....


因为这两天沉浸在失败的打击下,没心情整理东西,今天有空整理一下吧..........


第一题:

考点:基本的输入输出和条件判断

问题A: 感恩节KK专场——送给新生的礼物

时间限制: 1 Sec 内存限制: 128 MB
提交: 636 解决: 191
[ 提交][ 状态][ 讨论版]

题目描述

学长KK要送给学弟学妹们礼物,他送给学弟每人一个礼物,送给学妹每人两个礼物。为什么?KK单身好多年了。 现在KK想知道他需要准备的礼物数目。注意:如果没有学妹,KK会十分伤心,就不会给任何人发礼物。

输入

给定一个整数t,表示有t(t<=30)组测试数据。每组测试数据有两个整数b(0<=b<=100)和g(0<=g<=100),表示学弟的人数和学妹的人数。

输出

每行输出一个整数,表示需要准备的礼物数。

样例输入

2
1 2
2 3

样例输出

5

#include<stdio.h>
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		int sum=a+2*b;
		if(b==0)
		{
			sum=0;
		}
		printf("%d\n",sum);
	}
	return 0;
}


第二题:

考点:循环和数组的使用,素数的判断

问题B: 感恩节KK专场——特殊的比赛日期

时间限制: 1 Sec 内存限制: 128 MB
提交: 396 解决: 102
[ 提交][ 状态][ 讨论版]

题目描述

KK今天参加河南理工大学ACM程序设计竞赛,他发现今天是11月29号,刚好11和29都是素数(只能被1和自己本身整除的数叫做素数),于是他想知道今年(2015年)的某天之前(不含当天)一共有多少天是月份和天数都是素数。

输入

第一行输入一个整数t(1<t<366),代表t组测试数据。

接下来每行输入一个日期,仅包含(月份和天数),格式形如(yy-dd)。

输入时保证日期全部属于合法日期。

输出

输入yy-dd天之前有多少天的日期同时满足yy和dd同时为素数。

样例输入

3
2-2
2-5
2-15

样例输出

0
2
6

#include<stdio.h>
int date[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int prime(int x)
{
	if(x==1)
	{
		return 0;
	}
	for(int i=2;i<x;++i)
	{
		if(x%i==0)
		{
			return 0;
		}
	}
	return 1;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int month,day,cnt=0;
		scanf("%d-%d",&month,&day);
		for(int i=2;i<=month;++i)
		{
			for(int j=1;(i<month)?j<=date[i]:j<day;++j)
			{
				if(prime(i)&&prime(j))
				{
					++cnt;
				}
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}


第三题:

考点:表面上考贪心,实质考脑神经....

问题C: 感恩节KK专场——考试来了

时间限制: 1 Sec 内存限制: 128 MB
提交: 481 解决: 117
[ 提交][ 状态][ 讨论版]

题目描述

很多课程马上就结课了,随之而来的就是可怕的考试啦。现在KK学长即将迎来n场考试,为了不挂科,他必须复习完这n门课程。但是KK学长比较贪玩,一天只会花费a时间和b精力去复习。已知距离考试还有d天,问KK学长能不能复习完所有的功课。

输入

给定一个整数t,表示有t(t<=50)组测试数据。每组测试数据第一行有一个整数n(1<=n<=100),表示课程数目。 接下来一行有三个整数a,b,d(0<=a,b,d<=1000),代表上面提到的信息。下面有n行,每行有两个整数T[i],E[i](0<=T[i],E[i]<=1000),表示KK学长复习第i门课程,需要花费时间T[i],消耗精力E[i]。

输出

若KK学长可以复习完所有的课程,输出YES,否则输出NO。输出占一行。

样例输入

1
5
2 3 4
1 1 
1 1 
1 1
1 1
1 1

样例输出

YES


本次比赛漏洞最大的一道题!

这个题的正解应该是时间和精力同时计算,但是标程竟然把时间和精力分开计算了,然后当事人解释说,时间或者精力有剩余的话,可以学一部分某一课程,也就是说时间和精力直接累加就可以了

牵强的解释,试问,如果某个阶段只剩下时间或者只剩下精力,怎么可能进行正常的复习,难道复习消耗时间的时候不消耗精力,消耗精力的时候不消耗时间吗?

也就是说正解应该是时间和精力是不能直接分开计算的!!

而有些人用的也是贪心的思想整块考虑的,但是考虑科目去遍历消耗和考虑消耗去遍历科目的,两种本该一样的方法,一个错了,一个因为数据太弱ac了,呵呵,无言以对!!


虽然自己决定不了对错,但是坚持自己认为对的就行了!

自己的 “错误代码”:


比较暴力的遍历,加上标记可以省去一些时间

#include<stdio.h> 
#include<string.h> 
struct xx 
{ 
    int t,e; 
}x[1005],y[1005]; //x是复习需要,y模拟的天数  
//int vis[1005]; 
int main() 
{ 
    int t; 
    scanf("%d",&t); 
    while(t--) 
    { 
        int n,a,b,d; 
        memset(x,0,sizeof(x)); 
        memset(y,0,sizeof(y));// 
        scanf("%d%d%d%d",&n,&a,&b,&d);  
        for(int i=0;i<n;++i) 
        { 
            scanf("%d%d",&x[i].t,&x[i].e); 
        } 
        for(int i=0;i<d;++i) 
        { 
            y[i].t=a;y[i].e=b; 
        } 
        int cnt=0; 
        for(int i=0;i<n;++i)//课  
        { 
            for(int j=0;j<d;++j)//遍历每一天 
            { 
                if(y[j].e>=x[i].e&&y[j].t>=x[i].t) 
                //时间够用  
                { 
                    ++cnt; 
                    //vis[j]=1; 
                    y[j].e-=x[i].e;y[j].t-=x[i].t; 
                    break; 
                } 
            } 
        } 
        if(cnt>=n) 
        { 
            printf("YES\n"); 
        } 
        else
        { 
            printf("NO\n"); 
        } 
    }  
} 


所谓的正解:

#include<stdio.h>
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,a,b,d,E=0,T=0,sum=0;
		scanf("%d%d%d%d",&n,&a,&b,&d);
		for(int i=0;i<n;++i)
		{
			int t1,t2;
			scanf("%d%d",&t1,&t2);
			T+=t1;E+=t2;
		}
		if(T<=d*a&&E<=d*b)
		{
			printf("YES\n");
		}
		else
		{
			printf("NO\n");
		}
	}
	return 0;
}



第四题:

考点:简单数学知识+思维


问题D: 感恩节KK专场——2015年的第一场雪

时间限制: 1 Sec 内存限制: 128 MB
提交: 887 解决: 83
[ 提交][ 状态][ 讨论版]

题目描述

下雪了,KK学长站在三教门口,看学弟学妹们堆雪人。突然KK学长发现一个神奇的规律:春秋大道上能被k整除的位置都会有一个雪人。现在KK学长想知道春秋大道的[x, y]区间里面有多少个雪人。

输入

给定一个整数t,表示有t(t<=6000)组测试数据。每组测试数据有三个整数k(k非0且|k|<=2^30),x,y(x<=y且|x|,|y|<=2^30)。

输出

每行输出一个整数,表示雪人的个数。

样例输入

1
1 1 2

样例输出

2

可以说完完全全是简单的数学题了.......


#include<stdio.h>
//学校oj 不支持数学函数库,醉了 
int abs(int x)
{
	return x>0?x:-x;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int k,x,y;
		scanf("%d%d%d",&k,&x,&y);
		int a=abs(x/k),b=abs(y/k),sum;
		if(x*y>=0)
		{
			sum=abs(a-b);
			if((abs(x)>abs(y)?y:x)%k==0)//判断距离原点最近的那一个点 
			{
				++sum;
			} 
		}
		else
		{
			sum=a+b+1;
		}
		printf("%d\n",sum);
	}
	return 0;
}



第五题:

考点:简单递推+打表

问题E: 感恩节KK专场——爬楼梯

时间限制: 1 Sec 内存限制: 1000 MB
提交: 388 解决: 93
[ 提交][ 状态][ 讨论版]

题目描述

来机房比赛的时候大家都会爬楼梯,但是每个人可以迈出的最大步子不一样,所以到达机房的方案数也会不同。现在KK提出一个问题:目的地在第n层楼梯,我们在第1层,已知我们每次最多可以迈出3个台阶。问有多少种方案可以到达目的地。

输入

给定一个整数t,表示有t组测试数据(t>=10000)。每组测试数据有一个整数n(1<=n<=30),代表有n阶楼梯。

输出

每行输出一个整数,表示方案数。

样例输入

3
1
2
3

样例输出

0
1
2


倒数第二坑的题,因为这个题有一个特殊的地方,标程都没考虑到,然后全体一直wa....导致每个人都在怀疑自己的脑细胞是不是不够用:这么简单的规律都推导错了..........

其实是标程有问题..........

后来题目重新评判,才算解决.............


#include<stdio.h>
int main()
{
	int t,x[35];
	x[1]=0;x[2]=1;x[3]=2;x[4]=4;
	for(int i=5;i<35;++i)
	{
		x[i]=x[i-1]+x[i-2]+x[i-3];
	} 
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		printf("%d\n",x[n]);
	}
	return 0;
}



第六题:

考点:贪心算法求最多不重合区间

问题F: 感恩节KK专场——面试难题

时间限制: 1 Sec 内存限制: 128 MB
提交: 311 解决: 45
[ 提交][ 状态][ 讨论版]

题目描述

有n个人要来面试学生会XX部门,要求面试过程中任意两个面试者之间的时间不能有重叠。已知n个面试者到来的时间和需要面试的时间,问最多可以面试多少个人。该部门的XX是KK的好友,现在他来找KK帮忙。但是KK很忙,请你帮帮KK吧。时间重叠如[1, 3] [2, 4]或者[1, 3][3, 4]。

输入

给定一个整数t,表示有t(t<=100)组测试数据。每组测试数据有一个整数n(0<=n<=1000),接下来每行有两个整数S[i],T[i],表示第i个面试到来的时间和需要面试的时间。

输出

每行输出一个整数,表示最多可以面试的人数。

样例输入

1
1 
1 0

样例输出

1

这个题考的是贪心算法,先排序,然后进行贪心计算.....


#include<stdio.h>
#include<algorithm>
using namespace std;
struct node
{
	int l,s,e;
}x[1005];
int cmp(node a,node b)
{
	if(a.e==b.e)
	{
		return a.s<b.s;
	}
	return a.e<b.e;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<n;++i)
		{
			scanf("%d%d",&x[i].s,&x[i].l);
			x[i].e=x[i].s+x[i].l;
		}
		sort(x,x+n,cmp);
		int cnt=0,time=-1;
		for(int i=0;i<n;++i)
		{
			if(time<x[i].s)
			{
				++cnt;
				time=x[i].e;
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}



第七题:

考点:最短路

问题G: 感恩节KK专场——与学妹滑雪

时间限制: 1 Sec 内存限制: 128 MB
提交: 335 解决: 39
[ 提交][ 状态][ 讨论版]

题目描述

这周下的雪好大好大,不过这正和KK学长之意。因为他要去陪学妹滑雪,谁知调皮的学妹要和KK比赛,无奈的KK只能应战。已知比赛场地有n个站点,m条路线。比赛起点是第一个站点,终点是第n个站点,先到达终点的人是胜者(如果KK和学妹同时到,KK会认输)。现在KK为了显示学长风范,决定让学妹先滑T秒。但是到了比赛的时候,KK就有点后悔了。已知学妹到达终点需要时间Tg秒,KK每秒可以滑k米。现在问你KK在最优情况下能否赢得比赛。

输入

给定一个整数t,表示有t(t<=20)组测试数据。每组测试数据有两个整数n(1<=n<=1000),m(1<=m<=10000),接下来m行表示路线,每行三个整数a,b,c分别表示路线起点,终点,长度。最后一行有两个个整数T(1<=T<=10),Tg(1<=Tg<=10000)和一个实数k(0<=k<=200)表示上面提到的信息。

输出

若KK可以获胜输出"Good job,KK!",否则输出"What a pity!"。输出占一行。

样例输入

1
2 1
1 2 3
1 1 1

样例输出

What a pity!

提示

要求精度>=1e-3


算法题,最短路,最坑的是最后一句话......精度要求,自己马虎没注意,也怪不得别人,唉....

后来注意到精度了,还是错了很多才过去...........还要继续努力啊....


#include<stdio.h>
#include<string.h> 
#define inf 0x3f3f3f3f
#include<algorithm>
using namespace std;
int map[1005][1005],n,m;
int dijkstra()//最短路模板
{
	int vis[1005],dis[1005];
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[1]=0;
	while(1)
	{
		int v=-1;
		for(int i=1;i<=n;++i)
		{
			if(!vis[i]&&((v==-1)||(dis[i]<dis[v])))
			{
				v=i;
			}
		}
		if(v==-1)
		{
			break;
		}
		vis[v]=1;
		for(int i=1;i<=n;++i)
		{
			dis[i]=min(dis[v]+map[v][i],dis[i]);
		}
	}
	return dis[n];
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
	
		scanf("%d%d",&n,&m);
		memset(map,inf,sizeof(map));
		for(int i=0;i<m;++i)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			map[a][b]=map[b][a]=min(c,map[a][b]);
		}
		int T,tg;double k,s;
		scanf("%d%d%lf",&T,&tg,&k);
		s=dijkstra()*1.0/k+T;//男生的总时间 
		if(tg-s>=1e-3)'//注意条件控制
		{
			printf("Good job,KK!\n");
		} 
		else
		{
			printf("What a pity!\n");
		} 
	}
	return 0;
}


第八题:

考点:数学知识 幻方

问题 H: 感恩节KK专场——陪学妹上课

时间限制: 1 Sec 内存限制: 128 MB
提交: 49 解决: 23
[ 提交][ 状态][ 讨论版]

题目描述

KK和学妹一起去上线性代数课,号称“数学小王子”的KK,听数学课就犯困,为了使KK不睡觉,学妹决定给KK玩一个游戏,来激发KK。

游戏是这样的:给出一个N*N的矩阵,矩阵中分别填入1--N*N个数字,不允许重复,使得矩阵中每行、每列以及每条对角线上的数字之和,全部相等。

为了降低难度,学妹告诉KK,每组测试数据的第一行的正中间的数字一定为1。数据保证N为奇数。

输入

给定一个整数t(0<t<1000),表示有t组测试数据。

每组测试数据有一个奇数N(0<N<200),表示填上N*N个数字。

输出

每组测试数据输出一个N*N的矩阵,每个数字占8位,右对齐,具体格式见输出样例。

样例输入

2
3
5

样例输出

       8       1       6
       3       5       7
       4       9       2
      17      24       1       8      15
      23       5       7      14      16
       4       6      13      20      22
      10      12      19      21       3
      11      18      25       2       9

奇数阶幻方......

好麻烦的东西,网上只能找到做法,但是没有解释原因..........

算了,这个复杂爱的学术问题还是不研究了吧.......

网上的各种代码都特别恶心,倒不如自己写的清新脱俗,巧妙利用数组的下标取余就可以了........


#include<stdio.h>
#include<string.h>
int x[205][205];
int main()
{
	int t,n;
	//freopen("shuju.txt","r",stdin);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		memset(x,0,sizeof(x));
		int a=n-1,b=n/2,cnt=1;
		while(cnt<=n*n)
		{
			if(x[a%n][b%n])
			{
				a-=2;--b;
			}
			x[a++%n][b++%n]=cnt++;
		}
		for(int i=n-1;i>=0;--i)
		{
			for(int j=0;j<n;++j)
			{
				printf("%8d",x[i][j]);
			}
			printf("\n");
		}
	}
	return 0;
}


第九题:

考点:线段树:延迟更新,区间最值,区间离散化

1721: 感恩节KK专场——雪人的高度

时间限制: 1 Sec 内存限制: 128 MB
提交: 77 解决: 34
[ 提交][ 状态][ 讨论版]

题目描述

大雪过后,KK决定在春秋大道的某些区间上堆雪人。现在KK遇到了一道统计雪人高度的难题,请你帮帮他吧。注:KK堆雪人前春秋大道上是没有雪人的即所有位置雪人高度为0。

输入

给定一个整数t,表示有t(t<=5)组测试数据。每组测试数据有两个整数N(1<=N<=200000),表示N次操作。

操作分四种:
U1 x y v [x, y]位置的雪人高度减v

U2 x y v [x, y]位置的雪人高度加v

Q1 x y 查询[x, y]之间雪人的最大高度
Q2 x y 查询[x, y]之间雪人的最小高度

注: (|x|, |y|<=2^30, |v|<=100)

若上面的操作使某个位置的雪人高度为负,我们认为这种情况是合法的。

输出

对每个查询输出结果,结果占一行。结果保证不会超int。

样例输入

1
2
U2 -1000 1000 1
Q1 1000 10001

样例输出

1

这道题数据范围比较大,需要离散化处理,自己也是刚刚看明白大神写的最简单的坐标离散化:

也就是让每个数对应唯一的数组下标,然后利用下标就行各种线段树的操作,另外加上区间延迟更新......

此外注意要初始化..........


#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 1600005
using namespace std;
int maxtree[maxn],mintree[maxn],add[maxn],hash[maxn/4];
int li[200005],ri[200005],si[200005];
char op[200005][3];
void init()//初始化必要的数组 
{
	memset(add,0,sizeof(add));
	memset(maxtree,0,sizeof(maxtree));
	memset(mintree,0,sizeof(mintree));
}
void pushdown(int rt)
{
	if(add[rt])
	{
		int tp=rt<<1;
		add[tp]+=add[rt];add[tp|1]+=add[rt];//延迟标记下移 
		mintree[tp]+=add[rt];mintree[tp|1]+=add[rt];
		maxtree[tp]+=add[rt];maxtree[tp|1]+=add[rt];
		add[rt]=0;
	}
}

void update(int rt,int l,int r,int a,int b,int c,int p)
{
	if(l>=a&&r<=b)
	{
		if(p==1)//减少 
		{
			 add[rt]-=c;
			 maxtree[rt]-=c;mintree[rt]-=c;//对当前节点进行操作 
		}
		else//增加 
		{
			add[rt]+=c;
			maxtree[rt]+=c;mintree[rt]+=c;
		}
		return;
	}
	pushdown(rt);
	int mid=(l+r)>>1,tp=rt<<1;
	if(mid>=a)
	{
		update(tp,l,mid,a,b,c,p);
	}
	if(mid<b)
	{
		update(tp|1,mid+1,r,a,b,c,p);
	}
	mintree[rt]=min(mintree[tp],mintree[tp|1]);
	maxtree[rt]=max(maxtree[tp],maxtree[tp|1]);
}

int find(int rt,int l,int r,int a,int b,int p)
{
	if(l>=a&&r<=b)
	{
		if(p==1)
		{
			return maxtree[rt];
		}
		return mintree[rt];
	}
	pushdown(rt);
	int mid=(l+r)>>1,tp=rt<<1,kase=(p==1?-1<<30:1<<30);
	if(mid>=a)//左边 
	{
		if(p==1)//求最大 
		{
			kase=max(kase,find(tp,l,mid,a,b,p)); 
		}
		else
		{
			kase=min(kase,find(tp,l,mid,a,b,p));
		}
	}
	if(mid<b)//右边 
	{
		if(p==1)//求最大 
		{
			kase=max(kase,find(tp|1,mid+1,r,a,b,p)); 
		}
		else
		{
			kase=min(kase,find(tp|1,mid+1,r,a,b,p));
		}
	}
	return kase;
}

int main()
{
	int t,n;
	//freopen("shuju.txt","r",stdin);
	scanf("%d",&t);
	while(t--)
	{
		int k=1;init();
		scanf("%d",&n);
		for(int i=0;i<n;++i)
		{
			scanf("%s%d%d",op[i],&li[i],&ri[i]);
			if(op[i][0]=='U')
			{
				scanf("%d",&si[i]);
			}
			hash[k++]=li[i];hash[k++]=ri[i];
		}
		sort(hash+1,hash+k);
		k=unique(hash+1,hash+k)-hash-1;
		for(int i=0;i<n;++i)
		{
			int a=lower_bound(hash+1,hash+k,li[i])-hash;
			int b=lower_bound(hash+1,hash+k,ri[i])-hash;
			if(a>b)//注意这个坑!!!
			{
				swap(a,b); 
			} 
			if(op[i][0]=='U')
			{
				update(1,1,k,a,b,si[i],op[i][1]-'0');
			}
			else
			{
				printf("%d\n",find(1,1,k,a,b,op[i][1]-'0'));
			}
		}
	}
	return 0;
}




最后一个题比较复杂,个人能力暂时不会做,有机会再补上......



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值