题目大意
纯属是一个大模拟,四千多的码量太吓人了
模拟C++的结构体,有四种操作:
- 定义一个新的结构体,每个变量的地址都要对齐其对齐要求,即初始位置在对齐要求的倍数上,问这一个结构体所占用的地址大小(为对齐要求的倍数)和这个结构体的对齐要求(变量中最大的对齐要求)。
- 创建一个变量,对应一个结构体,问这一变量的起始地址。
- 给出一个询问途径,问这所对应的变量的起始地址
- 给出一个地址,问这个地址所对应的变量(若没有输出"ERR")
其中基础结构体变量有byte、short、int、long,对齐要求分别是1、2、4、8
题目分析
定义
由于“结构体”和“变量”的关系比较复杂,内部信息也很多,于是可定义这两者的结构体:
struct Struct{
long long size,large;//结构体的对齐要求、大小
char name[M];//结构体的名字
long long len;//结构体的名字长度(没用)
long long sum;//结构体内部的变量数量
char son[N][M];//内部变量
long long son_str[N];//每个变量对应的结构类型
}a[N];
struct Variable{
long long str_note;//变量类型
long long len;//名字长度
char name[M];//变量名字
long long fir,lst;//变量在真实地址中的起始和结束位置(没用)
}x[N];
小贴士
int等基础类型
我们可以发现byte,short,int,long这四个变量可以当做一个没有子变量的结构体。发现这个可以减少很多码量
//a为结构体
a[1].name[0]='b',a[1].name[1]='y',a[1].name[2]='t',a[1].name[3]='e';a[1].large=a[1].size=1;
a[2].name[0]='s',a[2].name[1]='h',a[2].name[2]='o',a[2].name[3]='r',a[2].name[4]='t';a[2].large=a[2].size=2;
a[3].name[0]='i',a[3].name[1]='n',a[3].name[2]='t';a[3].large=a[3].size=4;
a[4].name[0]='l',a[4].name[1]='o',a[4].name[2]='n',a[4].name[3]='g';a[4].large=a[4].size=8;
对齐
对齐的意义就是将这个变量或结构体的地址起点为其要求的倍数,即:
long long up(long long large,long long size){//large:当前地址 size:对齐要求
if(large%size!=0)large=(large/size+1)*size;
return large;
}
操作
1
对于1操作,我们可以每进入一个变量就用 O ( n ) O(n) O(n)的时间暴力判断每个变量的类型,进行更新结构体大小、对齐要求等结构体的基本属性,最后将结构体大小对齐一下即可。折合 O ( n 2 ) O(n^2) O(n2)
scanf("%s",a[++cnt].name);//读入结构体名字
a[cnt].len=strlen(a[cnt].name);
scanf("%lld",&a[cnt].sum);//读入变量数量
for(i=1;i<=a[cnt].sum;i++){
scanf("%s",s);//读入变量类型
for(j=1;j<cnt;j++)//暴力枚举类型
if(strcmp(s,a[j].name)==0){
a[cnt].son_str[i]=j;
a[cnt].size=max(a[cnt].size,a[j].size);
a[cnt].large=up(a[cnt].large,a[j].size);
a[cnt].large+=a[j].large;
break;
}
len=strlen(s);for(j=0;j<=len;j++)s[j]=0;//清空s数组
scanf("%s",a[cnt].son[i]);//读入变量名字
}
a[cnt].large=up(a[cnt].large,a[cnt].size);
printf("%lld %lld\n",a[cnt].large,a[cnt].size);
2
对于2操作,我们同样可以暴力枚举变量类型,然后在地址上标记一下它的起始位置,并将已使用的地址上限更新。
scanf("%s",s);
len=strlen(s);
scanf("%s",x[++num].name);
x[num].len=strlen(x[num].name);
for(i=1;i<=cnt&&!x[num].str_note;i++)//寻找结构类型
if(strcmp(s,a[i].name)==0)
x[num].str_note=i;
where=up(where,a[x[num].str_note].size);//对齐
printf("%lld\n",where);
x[num].fir=where;
where+=a[x[num].str_note].large;
x[num].lst=where-1;
len=strlen(s);
for(i=0;i<=len;i++)
s[i]=0;
3
对于操作3,我们可以将整个查询途径记录下来,然后不断暴力寻找名字重合的变量( O ( n 2 ) O(n^2) O(n2)),折合起来 O ( n 3 ) O(n^3) O(n3)
scanf("%s",S);
len=strlen(S);
now=0,first=1;
for(i=0;i<len;i++){
Len=strlen(s);//清空
for(j=0;j<=Len;j++)
s[j]=0;
j=0;
while(S[i]!='.'&&i<len){//取出其中的名字
s[j++]=S[i];
S[i++]=0;
}
S[i]=0;
if(first){//最外层变量
now_name=0;
for(j=1;j<=num&&!now_name;j++)//暴力寻找
if(strcmp(s,x[j].name)==0)
now_name=j;
now=x[now_name].fir;
now_str=x[now_name].str_note;
first=0;
continue;
}//结构体内变量
now_name=0,u=0;
for(j=1;j<=a[now_str].sum&&!now_name;j++){
u=up(u,a[a[now_str].son_str[j]].size);
if(strcmp(s,a[now_str].son[j])==0)now_name=j;
else u+=a[a[now_str].son_str[j]].large;
}
now+=u;//更新变量
now_str=a[now_str].son_str[now_name];
}printf("%lld\n",now);
Len=strlen(s);//清空
for(j=0;j<=Len;j++)
s[j]=0;
4
对于操作4,还是直接暴力,然后寻找地址是否合法
scanf("%lld",&now);
if(now>=where){//特判超过最大范围
printf("ERR\n");
break;
}
u=0;
for(i=1;i<=num;i++){//寻找第一层
u=up(u,a[x[i].str_note].size);
if(now-u<a[x[i].str_note].large){
now_name=i;
break;
}
u+=a[x[i].str_note].large;
}
now-=u;
if(now<0||!now_name){//判断是否合法
printf("ERR\n");
break;
}
Len=0;
for(i=0;i<x[now_name].len;i++)
S[Len++]=x[now_name].name[i];//添加后缀名字
now_str=x[now_name].str_note;
while(now_str>4){//不是基础变量
now_name=0,u=0,v=0;
for(i=1;i<=a[now_str].sum;i++){//查找内部变量
v=u;
u=up(u,a[a[now_str].son_str[i]].size);
if(now-u<a[a[now_str].son_str[i]].large){
now_name=i;
break;
}
u+=a[a[now_str].son_str[i]].large;
}
now-=u;
if(now<0){//判断不合法
now_str=0;
break;
}
S[Len++]='.';
for(i=0;i<strlen(a[now_str].son[now_name]);i++)
S[Len++]=a[now_str].son[now_name][i];//添加后缀
now_str=a[now_str].son_str[now_name];
}
if(now_str)printf("%s",S);
else printf("ERR");
Len=strlen(S);
for(i=0;i<=Len;i++)S[i]=0;//清空
printf("\n");
总结
这道题还是很水的但是码量是真的长
一定要记得清空数组啊!!!