您的位置:首页 > 其它

2017年3月23日考试总结

2017-03-26 17:21 309 查看
第一题:原子核研究
题目描述:
最近物理学家正在研究一些新的原子,称为X族。他们发现该族中的元素非常相近,但是其质量都不相同。质量越接近的越容易相互转化。现在,物理学家已经发明了一种设备,可以对X族的元素来进行以下三种操作:
1.generate M 产生质量为M的一个元素,如果已经存在,则该操作不产生作用。
2.romove M 销掉质量为M的元素,如果不存在质量为M的元素,则该操作不产生作用。
3.query 查询X族中质量最接近的两种元素的质量差的绝对值。如果此时X族中的元素个数小于2,则输出-1.
现在,请你写一个程序来模拟该设备的操作。
输入:输入包含多组测试数据,第一行一个整数t,表示测试数据的组数。对于每一组数据,第一行是一个整数n,表示有n条指令。接下来n行,每行表示一条指令,如上所述。M是一个正整数,不超过100000.
题解:其实就是普通的AVL数,同时维护每一子树上的Max,Min,ans(data-左子树最大或右子树最小-data),正常查询即可。
成绩:10
分析:考试的时候光想到最大最小,没有维护ans查询时也没有搜下去。觉得第一题比较简单,然后也没有特意地编数据,TAT233333.
 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
using namespace std;
const int N=100000+10;
const int inf=0x3f3f3f3f;
void getint(int&num){
char c;int flag=1;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
num*=flag;
}
struct node{
int data,lc,rc,h,sum,Max,Min,ans;
node(){ans=inf;}
}tree
;
int T,t,n,r,cnt;
char op[10];
int abs(int x){
return x>0?x:-(x);
}
void update_high(int root){
tree[root].h=max(tree[tree[root].lc].h,tree[tree[root].rc].h)+1;
tree[root].sum=tree[tree[root].lc].sum+tree[tree[root].rc].sum+1;
int tmp1,tmp2,tmp3,tmp4;
tmp1=tmp2=tmp3=tmp4=inf;
if(tree[root].rc){
tree[root].Max=tree[tree[root].rc].Max;
tmp1=tree[tree[root].rc].ans,tmp2=tree[tree[root].rc].Min-tree[root].data;
}
else tree[root].Max=tree[root].data;
if(tree[root].lc){
tree[root].Min=tree[tree[root].lc].Min;
tmp3=tree[tree[root].lc].ans,tmp4=tree[root].data-tree[tree[root].lc].Max;
}
else tree[root].Min=tree[root].data;
tree[root].ans=min(min(tmp1,tmp2),min(tmp3,tmp4));
}
int zig(int root){
int t=tree[root].lc;
tree[root].lc=tree[t].rc,tree[t].rc=root;
update_high(root),update_high(t);
return t;
}
int zag(int root){
int t=tree[root].rc;
tree[root].rc=tree[t].lc,tree[t].lc=root;
update_high(root),update_high(t);
return t;
}
int zigzag(int root){
tree[root].rc=zig(tree[root].rc) ;
return zag(root) ;
}
int zagzig(int root){
tree[root].lc=zag(tree[root].lc) ;
return zig(root);
}
void maintain(int &root){
if(tree[tree[root].lc].h==tree[tree[root].rc].h+2){
int t=tree[root].lc;
if(tree[tree[t].lc].h==tree[tree[root].rc].h+1) root=zig(root);
else if(tree[tree[t].rc].h==tree[tree[root].rc].h+1) root=zagzig(root);
}
else if(tree[tree[root].rc].h==tree[tree[root].lc].h+2){
int t=tree[root].rc;
if(tree[tree[t].rc].h==tree[tree[root].lc].h+1) root=zag(root);
else if(tree[tree[t].lc].h==tree[tree[root].lc].h+1) root=zigzag(root);
}
update_high(root);
}
int insert(int root,int x){
if(!root){
tree[++cnt].data=x;
tree[cnt].sum=tree[cnt].h=1;
tree[cnt].Max=tree[cnt].Min=x;
tree[cnt].lc=tree[cnt].rc=0;
tree[cnt].ans=inf;
return cnt;
}
else if(x<tree[root].data)
tree[root].lc=insert(tree[root].lc,x);
else if(x>tree[root].data)
tree[root].rc=insert(tree[root].rc,x);
maintain(root);
return root;
}
int del(int &root,int x){
int res;
if(tree[root].data==x||(x<tree[root].data&&!tree[root].lc)||(x>tree[root].data&&!tree[root].rc)){
res=tree[root].data;
if(!tree[root].lc||!tree[root].rc){
root=tree[root].lc+tree[root].rc;return res;
}
else tree[root].data=del(tree[root].lc,x);
}
else{
if(x<tree[root].data) res=del(tree[root].lc,x);
else res=del(tree[root].rc,x);
}
maintain(root);
return res;
}
bool find(int val){
int x=r;
while(x){
if(tree[x].data==val) return 1;
else if(tree[x].data>val) x=tree[x].lc;
else x=tree[x].rc;
}
return 0;
}
int main(){
//freopen("atomic1.in","r",stdin);
//freopen("1.out","w",stdout);
getint(T);
while(T--){
getint(t),cnt=r=0;
while(t--){
scanf("%s",op);
if(op[0]=='q') printf("%d\n",tree[r].sum>1?tree[r].ans:-1);
else{
getint(n);
if(op[0]=='g') r=insert(r,n);
else if(find(n)) del(r,n);
}
}
putchar(10);
/*for(int i=0;i<=cnt;i++){
tree[i].lc=tree[i].rc=0;
tree[i].data=tree[i].h=tree[i].sum=0;
tree[i].Max=-inf,tree[i].Min=inf,tree[i].ans=inf;
}*/
}
return 0;
}
第二题:题目描述
给出球星们的能力值、年份、名字,有很多个查询,每个查询给出一个年份的范围,求出这个范围里能力值从高到低排列的前11名球员,如果能力值相同则按年份从低到高排,如果年份仍然相同,则按名字的字典序排。如果不足11个球员,就用XXX代替输出凑够11行。
 
输入:第一行包含1个整数N(1<=N<=50000),表示球星的总数,接下来N行,每行描述了1个球星(year,name,ability)。0<=year<=1000000000,name不超过15个字母,0<=ability<=1000000000.
假设没有两个人的名字相同。接下来有一个整数R(R<=100000),表示有R个查询。接下来R行,每行描述了一个产寻,每个查询包含2个整数(x,y),表示从第x年到第y年。(0<=x<=y<=1000000000)
输出:对于每组数据,按上面描述的顺序输出最靠前的11个球员的名字,每个球员占一行。如果不足11行,则用XXX代替,凑够11行。每组数据后都有一个空行。
成绩:0
题解:把year离散化,线段树,结构体里开一个优先队列,保证里面不超过11个元素。
分析:其实考试时想到了正确思路,但写代码时犯了两个错误,首先:数组开小了,球星加上询问一起需要离散化的元素有2R+N个,但习惯性打成了N233,然后“每个查询给出一个年份的范围,求出这个范围里能力值从高到低排列的前11名球员,如果能力值相同则按年份从低到高排,如果年份仍然相同,则按名字的字典序排”这一句话,读题时还标注了,最后写代码是能力值相同就直接名字字典序了。
 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#define lson num<<1
#define rson num<<1|1
using namespace std;
const int N=50000+10;
const int inf=0x3f3f3f3f;
void getint(int&num){
char c;int flag=1;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
num*=flag;
}
struct p{
int year,data;
char name[20];
p(){memset(name,0,sizeof(name));}
bool operator < (const p &x)const{
if(data!=x.data)return data>x.data;
else if(year!=x.year)return year<x.year;
else return strcmp(name,x.name)<0;
}
}star
,tmp,B[300000];
struct node{
int l,r;
priority_queue<p> ans;
}tree[300000<<2];
int n,T,tot,cnt,Y[300000],ask[2];
map<int,int> q;
priority_queue <p> A;
queue <p> b;
void build(int num,int l,int r){
tree[num].l=l,tree[num].r=r;
while(!tree[num].ans.empty())
tree[num].ans.pop();
if(l==r) return ;
int mid=(l+r)>>1;
build(lson,l,mid),build(rson,mid+1,r);
}
void insert(int num,p x){
if(tree[num].r<x.year||tree[num].l>x.year) return ;
tree[num].ans.push(x);
while(tree[num].ans.size()>11) tree[num].ans.pop();
int mid=(tree[num].l+tree[num].r)>>1;
if(x.year<=mid) insert(lson,x);
else insert(rson,x);
}
void search(int num,int l,int r){
if(tree[num].l>r||tree[num].r<l) return ;
else if(tree[num].l>=l&&tree[num].r<=r){
while(!tree[num].ans.empty())
b.push(tree[num].ans.top()),tree[num].ans.pop();
while(!b.empty()){
A.push(b.front());
while(A.size()>11) A.pop();
tree[num].ans.push(b.front()),b.pop();
}
}
else search(lson,l,r),search(rson,l,r);
}
bool cmp(p a,p b){
return a.year<b.year;
}
int find(int w){
int l=0,r=n,mid;
int ans=0;
while(l<=r){
mid=(l+r)>>1;
if(Y[mid]<w) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
int main(){
getint(n);
for(int i=1;i<=n;i++)
getint(star[i].year),scanf("%s",star[i].name),getint(star[i].data);
sort(star+1,star+n+1,cmp);
cnt=1;
for(int i=1;i<=n;++i){
Y[i]=star[i].year;
if(star[i].year!=star[i+1].year)star[i].year=cnt++;
else star[i].year=cnt;
}
cnt--;
build(1,1,cnt);
for(int i=1;i<=n;i++)
insert(1,star[i]);
getint(T);
while(T--){
getint(ask[0]),getint(ask[1]);
while(!A.empty()) A.pop();
ask[0]=star[find(ask[0])+1].year;
ask[1]=star[find(ask[1]+1)].year;
search(1,ask[0],ask[1]);
int now=0;
while(!A.empty())
B[++now]=A.top(),A.pop();
sort(B+1,B+now+1);
for(int i=1;i<=now;i++)
printf("%s\n",B[i].name);
for(now=now+1;now<=11;now++)printf("XXX\n");
putchar(10);
}
}

第三题:题目描述:公园中有许多木桩,每个木桩都有一个高度,活泼的小 z
同学喜欢从一个木桩跳到另一个木桩上,zn
说太危险了,于是 z
同学让 zn
算出每一次跳跃的危险系数。小z
每一次跳 跃的范围是一个 k * k
的矩形,危险系数为这个矩形内最高的木桩高度减去最小的。身为 oier, 你能比学数奥的
zn 算的快吗
输入:第一行三个整数 n(木桩为
n ∗
n 的矩阵)、k、b(小
zz 准备跳跃的次数) 接下来为
n ∗
n 的矩阵,描述木桩的高度接下来
b 行;每行两个整数
x, y(表示
z 同学跳跃的范围的左上角为第
x 行第
y列), 保证跳跃范围不超过矩阵的范围
【数据范围】对于30%的数据
0 < k ≤
n ≤
250,0 < b
≤ 100;
对于100%的数据
0 < k ≤
n ≤
250,0 < b
≤ 1000000
成绩:0
题解:二维线段树裸题
分析:两个巨大错误:1.数组开小了;2.build函数打错了。但即使打对了也只有30分,分析数据只有250*250,可询问最多有1000000个二250*250=62500,中间一定有重复的(x,y)询问,记录ans[x][y],有重复的直接输出即可。(这个真的没想到,还是考完几天听hyh说才发现2333)
 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<stack>
#include<algorithm>
#include<vector>
#define son1 (num<<2)-2
#define son2 (num<<2)-1
#define son3 num<<2
#define son4 num<<2|1
using namespace std;
const int N=300;
const int inf=0x3f3f3f3f;
void getint(int&num){
char c;int flag=1;num=0;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
num*=flag;
}
int n,k,T,x,y,Max,Min,arr

,ans

;
bool vis

;
struct node{
int x1,y1,x2,y2,Max,Min;
node(){Max=-inf,Min=inf;}
node(int a,int b,int c,int d,int e,int f){
x1=a,y1=b,x2=c,y2=d,Max=e,Min=f;
}
}tree[N*N*16];
void update(int num){
tree[num].Max=max(max(tree[son1].Max,tree[son2].Max),max(tree[son3].Max,tree[son4].Max));
tree[num].Min=min(min(tree[son1].Min,tree[son2].Min),min(tree[son3].Min,tree[son4].Min));
}
void build(int num,int x1,int y1,int x2,int y2){
tree[num]=node(x1,y1,x2,y2,-inf,inf);
if(x1==x2&&y1==y2){
tree[num].Max=tree[num].Min=arr[x1][y1];return ;
}
int midx=(x1+x2)>>1,midy=(y1+y2)>>1;
if(x1!=x2 &&y1!=y2){
build(son1,x1,y1,midx,midy);
build(son2,midx+1,y1,x2,midy);
build(son3,x1,midy+1,midx,y2);
build(son4,midx+1,midy+1,x2,y2);
}
if(x1==x2){
build(son1,x1,y1,x1,midy);
build(son3,x1,midy+1,x1,y2);
}
if(y1==y2){
build(son1,x1,y1,midx,y1);
build(son2,midx+1,y1,x2,y1);
}
update(num);
}
void getmax(int num,int x1,int y1,int x2,int y2){
if(tree[num].x1>x2||tree[num].x2<x1||tree[num].y1>y2||tree[num].y2<y1) return ;
else if(tree[num].x1>=x1&&tree[num].x2<=x2&&tree[num].y1>=y1&&tree[num].y2<=y2)
Max=max(tree[num].Max,Max);
else{
getmax(son1,x1,y1,x2,y2);
getmax(son2,x1,y1,x2,y2);
getmax(son3,x1,y1,x2,y2);
getmax(son4,x1,y1,x2,y2);
}
}
void getmin(int num,int x1,int y1,int x2,int y2){
if(tree[num].x1>x2||tree[num].x2<x1||tree[num].y1>y2||tree[num].y2<y1) return ;
else if(tree[num].x1>=x1&&tree[num].x2<=x2&&tree[num].y1>=y1&&tree[num].y2<=y2)
Min=min(tree[num].Min,Min);
else{
getmin(son1,x1,y1,x2,y2);
getmin(son2,x1,y1,x2,y2);
getmin(son3,x1,y1,x2,y2);
getmin(son4,x1,y1,x2,y2);
}
}
int main(){
getint(n),getint(k),getint(T),k--;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
getint(arr[i][j]);
build(1,1,1,n,n);
while(T--){
getint(x),getint(y),Max=-inf,Min=inf;
if(!vis[x][y]){
getmax(1,x,y,x+k,y+k),getmin(1,x,y,x+k,y+k);
ans[x][y]=Max-Min,vis[x][y]=1;
}
printf("%d\n",ans[x][y]);
}
return 0;
}
总结:总之考得非常炸非常炸非常炸非常炸非常炸非常炸非常炸非常炸非常炸非常炸233333。。。。。几次数据结构的考试除了树状数组基本都是这种效果,平时做题感觉自己数据结构其实还好,但考试时,有时代码量一大直接导致手残概率倍增,时间也比较紧,想思路时发现需要AVL什么的都很紧张(好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打好长啊不想打)处于人脑估计哪一题短就先做哪一题的纠结中。虽然不想承认,数据结构真的比我想象中水很多(尤其考试状态下,手残党的绝望)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: