CSP-S T3结构体


题目大意

纯属是一个大模拟,四千多的码量太吓人了
模拟C++的结构体,有四种操作:

  1. 定义一个新的结构体,每个变量的地址都要对齐其对齐要求,即初始位置在对齐要求的倍数上,问这一个结构体所占用的地址大小(为对齐要求的倍数)和这个结构体的对齐要求(变量中最大的对齐要求)。
  2. 创建一个变量,对应一个结构体,问这一变量的起始地址。
  3. 给出一个询问途径,问这所对应的变量的起始地址
  4. 给出一个地址,问这个地址所对应的变量(若没有输出"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");

总结

这道题还是很水的但是码量是真的长
一定要记得清空数组啊!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值