您的位置:首页 > 其它

2017NOIP普及模拟赛题解报告

2018-01-06 21:35 381 查看

比赛答案:

第一题:跳远

思路:

我们读入数据后,分2个循环,读入n组数据,然后先对每个人数据找出最大数,然后储存.之后对所有人的最大数进行排序,可以用冒泡或sort,输出即可

在输出方面,有点难度,我们可以:考虑用一用数组储存一个人的成绩的下标

什么意思?

也就是说-我们每个数组有2个元素,一个是这个人的数据…也是这个人的排名

另一个就是这个人的编号

可以用结构体实现

另一个思路:

我们可以开一个数组,叫book吧!

然后我们开始处理..把这个每个人的成绩储存进去

第一个人的成绩储存位置就是第一个数组元素

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
struct AS{
int a,i;
inline bool operator < (const AS & o) const{
return a>o.a;
}
//这是重载运算符...也可以自己手动实现
}a
;
int ans
;
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
static int tmp[3];
for(int j=3;j--;)scanf("%d",tmp+j);
a[i]=(AS){*max_element(tmp,tmp+3),i}; //这是找最大的数据的函数...自己到网上查...也可以自己手动写
}
sort(a+1,a+n+1);
for(int i=1;i<=n;++i)ans[a[i].i]=i;//也就是编号方法,有点难理解
for(int i=1;i<=n;++i)printf("%d%c",ans[i],i<n?' ':'\n');//3目运算符,可以改为if
}
return 0;
}


第二题:栈的操作

思路:嗯,这题有点难度,我们要模拟栈或使用strack(自己百度)

题意:模拟一个栈,接收一个由非负整数构成的操作序列a。若a_i>0则把a_i压进栈中,若a_i=0则取出栈顶的两个元素把它们的和压进栈中。最后输出栈顶的元素。

如果栈中没有元素,则取栈顶元素的操作会取出0.(可以视为初始时在栈中加入了足够多的0)

现在a中出现了一个未知变量,你知道最终的输出。求这个未知变量。(有多解输出最小的值,无解则输出-1)

分两种情况考虑:

①-1=>0,模拟一遍判断是否可行。

②-1=>正数. Ax=b,a∈{0,1}

x与最终答案相关=>若m-栈顶元素>0,输出m-栈顶元素,否则-1

x与最终答案无关=>栈顶元素与m相等,输出0否则-1.

Code

#include<bits/stdc++.h>
using namespace std;
//以后这个的意思是LL代表long long int!
typedef long long LL;
const int N=1e5+5;
bool flag[N<<1];
int a
;
void output(int x){
printf("%d\n",x);
exit(0);
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=0;i<n;++i)scanf("%d",a+i);
int m;
scanf("%d",&m);

static LL stack[N<<1];
int stot=n;
for(int i=0;i<n;++i)
if(a[i]<=0)
{
--stot;
stack[stot-1]+=stack[stot];
}
else stack[stot++]=a[i];
if(stack[--stot]==m)output(0);

stot=n;
memset(stack,0,sizeof(stack));
for(int i=0;i<n;++i)
switch(a[i]){
case -1:
stack[stot]=0,flag[stot++]=1;
break;
case 0:
--stot;
stack[stot-1]+=stack[stot];
flag[stot-1]|=flag[stot];
flag[stot]=0;
break;
default:
stack[stot++]=a[i];
break;
}

if(flag[--stot]&&m-stack[stot]>0)output(m-stack[stot]);
else output(-1);
}


第三题:游戏

思路:

对于前50%的数据,由于n<20,整个棋盘的状态个数 < 2^20。 由于状态数有限,我们可以采取记忆化搜索的办法来实现。

但对于100%的数据,n的最大可能值达到999,记忆化搜索就不怎么可行了。其实本题有一个更简单的做法:

考虑每个棋子到最右边格子的距离。把所有棋子这样的距离的总和计为s。我们发现不管选择两种操作中的一种操作,每走一步,s的奇偶性都会发生一次变化。所以说,如果第一次轮到明明时,s是奇数,那么每次轮到明明时s都是奇数。而当s是奇数时,s肯定>0,这时明明总可以走最右边的棋子。也就是说当s为奇数时,总有棋子可以走。所以说,一开始若s为奇数,则明明必胜。同理,若一开始s为偶数,则当亮亮走的时候s总是奇数,所以明明必败。

Code

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
//freopen("game.in", "r", stdin);
//freopen("game.out", "w", stdout);
int t;
scanf("%d", &t);

for (int tt = 0; tt < t; tt++)
{
int n;
scanf("%d\n", &n);
int  s = 0;
for (int i = 0; i < n; i++)
{
char c;
scanf("%c", &c);
if (c == 'o') s = s + (n - i - 1);
}
if (s % 2 == 1) printf("M\n"); else printf("L\n");
}
}


第四题:Hzwer之机器人

Code

#include<bits/stdc++.h>
using namespace std;
const int N=3000+5;
bool vst[N<<1][N<<1];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int moves
;
void over(){
puts("-1");
exit(0);
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",moves+i);
int mid=3001;
int x=mid,y=x;
int lx=x,rx=x,ly=y,ry=y;
for(int i=1;i<=n;++i){
x+=dx[i%4]*moves[i],y+=dy[i%4]*moves[i];
lx=min(lx,x),rx=max(rx,x);
ly=min(ly,y),ry=max(ry,y);
}
if(lx<mid-3000||ly<mid-3000||rx>mid+3000||ry>mid+3000)over();
for(int i=ly-1;i<=ry+1;++i)vst[lx-1][i]=vst[rx+1][i]=1;
for(int i=lx-1;i<=rx+1;++i)vst[i][ly-1]=vst[i][ry+1]=1;
vst[x=mid][y=mid]=1;
for(int i=1;i<=n;++i){
for(int j=moves[i];j--;){
x+=dx[i%4],y+=dy[i%4];
if(vst[x][y])over();
vst[x][y]=1;
}
if(i!=n&&!vst[x+dx[i%4]][y+dy[i%4]])over();
}
printf("%d\n",(rx-lx+1)*(ry-ly+1));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: