前天,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;
}
最后一个题比较复杂,个人能力暂时不会做,有机会再补上......