标签:std P9754 Obj 题解 align tnam offset now CSP
前言
在考场上调了 2h+ 还没调出来,并且 T4 也没来得及做。希望看到这段文字的你能避免这样的悲剧。
正文
题目要求动态创建类型,于是我用结构体代表一个 struct(禁止套娃),要新建就 new
出来一个。(最后也没 delete
)
struct Obj{
typnam tnam;
ll len, align;
std::map<std::string, std::pair<Obj*, ll>> subs;
Obj():tnam(), len(0), align(0){}
Obj(std::string nam, ll le=0, ll ali=0):tnam(nam), len(le), align(ali){}
};
由于结构体的名称和变量名称容易混淆,我用 typnam
标注了结构体的名称。
using typnam = std::string;
声明了结构体之后,题目要求根据名称找出一个结构体,我用 std::set
保存。这里也可以用 std::map
。
struct comp_obj_by_typnam{ bool operator()(Obj *a, Obj *b) const { return a->tnam < b->tnam; } };
std::set<Obj*, comp_obj_by_typnam> decl_objs = {&BByte, &SShort, &IInt, &LLong};
Obj *get_obj_by_tname(typnam &tnam){
Obj tmp(tnam);
return *decl_objs.find(&tmp);
}
对于已存在的变量,我用一个 map
保存名称,类型和起始位置。
其实这里也可以新建一个特殊的 struct,就像森林转树要加一个超级根一样。这样可以避免一些重复的代码。
std::map<std::string, std::pair<Obj*, ll>> exist_objs;
ll global_offset = 0;
关于如何计算对齐:
设第 \(i\) 个被定义的元素大小为 \(s_i\),对齐要求为 \(a_i\),起始地址为 \(b_i\);
则 \(b_1=0\),对于 \(2\le i\), \(b_i\) 为满足 \(b_{i−1}+s_{i−1} \le b_i\) 且 \(a_i\) 整除 \(b_i\) 的最小值。
记 \(k=b_{i-1}+s_{i-1}\),若 \(k \equiv 0 \pmod {a_i}\),则 \(b_i\) 正好可以放入;
否则,\(b_i = k+a_i-(k \bmod {a_i})\)。
ll get_start_addr(ll old_offset, Obj const *me){
if(old_offset % me->align) old_offset += me->align - old_offset%me->align;
return old_offset;
}
关于访问某个元素:
读入名称 s
后,可以用 s.substr(0, s.find("."))
找到 struct 名。
附完整代码,用于 debug:
完整代码
```cpp
#include
#define UP(i,s,e) for(auto i=s; i<e; ++i)="" namespace="" m{="" }{{{="" using="" std::cin;="" std::cout;="" typnam="std::string;" ll="long" long;="" struct="" obj{="" tnam;="" len,="" align;="" std::map<std::string,="" std::pair<obj*,="">> subs;
Obj():tnam(), len(0), align(0){}
Obj(std::string nam, ll le=0, ll ali=0):tnam(nam), len(le), align(ali){}
};
Obj BByte = {"byte", 1, 1},
SShort = {"short", 2, 2},
IInt = {"int", 4, 4},
LLong = {"long", 8, 8};
int in;
struct comp_obj_by_typnam{ bool operator()(Obj *a, Obj *b) const { return a->tnam < b->tnam; } };
std::map<std::string, std::pair<obj*,="" ll="">> exist_objs;
ll global_offset = 0;
std::set<obj*, comp_obj_by_typnam=""> decl_objs = {&BByte, &SShort, &IInt, &LLong};
Obj *get_obj_by_tname(typnam &tnam){
Obj tmp(tnam);
return *decl_objs.find(&tmp);
}
ll get_start_addr(ll old_offset, Obj const *me){
if(old_offset % me->align) old_offset += me->align - old_offset%me->align;
return old_offset;
}
void declare_struct(){
std::string is; int ik;
cin >> is >> ik;
Obj *now = new Obj;
now->tnam = is;
ll nowoff = 0;
UP(i, 0, ik){
std::string it, in;
cin >> it >> in;
Obj *me = get_obj_by_tname(it);
now->align = std::max(now->align, me->align);
nowoff = get_start_addr(nowoff, me);
now->subs.insert({in, {me, nowoff}});
nowoff += me->len;
}
now->len = get_start_addr(nowoff, now);
decl_objs.insert(now);
cout << now->len << ' ' << now->align << '\n';
}
void create_obj(){
std::string it, in;
cin >> it >> in;
Obj *now = get_obj_by_tname(it);
global_offset = get_start_addr(global_offset, now);
exist_objs.insert({in, {now, global_offset}});
cout << global_offset << '\n';
global_offset += now->len;
}
void access_obj_recursive(ll sum_offset, std::string &is, Obj *now){
auto pl = is.find('.');
if(pl == std::string::npos){
cout << sum_offset+now->subs[is].second << '\n';
return;
}
auto &now_info = now->subs[is.substr(0, pl)];
now = now_info.first;
is.erase(0, pl+1);
access_obj_recursive(sum_offset + now_info.second, is, now);
}
void access_obj(){
std::string is;
cin >> is;
auto pl = is.find('.');
if(pl == std::string::npos){
cout << exist_objs[is].second << '\n';
return;
}
auto &now_info = exist_objs[is.substr(0, pl)];
Obj *now = now_info.first;
is.erase(0, pl+1);
access_obj_recursive(now_info.second, is, now);
}
void access_addr_recursive(ll addr, Obj *now, std::string &ans){
if(now == &BByte || now == &SShort || now == &IInt || now == &LLong){
cout << ans << '\n';
return;
}
for(auto &i:now->subs){
if(i.second.second <= addr &&
i.second.second + i.second.first->len > addr){
ans += '.';
ans += i.first;
access_addr_recursive(
addr-i.second.second,
i.second.first,
ans);
return;
}
}
cout << "ERR\n";
}
void access_addr(){
ll addr; cin >> addr;
std::string ans;
for(auto &i:exist_objs){
if(i.second.second <= addr &&
i.second.second + i.second.first->len > addr){
ans = i.first;
access_addr_recursive(
addr-i.second.second,
i.second.first,
ans);
return;
}
}
cout << "ERR\n";
}
void work(){
cin >> in;
UP(i, 0, in){
int op;
cin >> op;
if(op == 1){
declare_struct();
} else if(op == 2){
create_obj();
} else if(op == 3){
access_obj();
} else {
access_addr();
}
}
}
} // {}}}
int main(){m::work(); return 0; }
```
标签:std,
P9754,
Obj,
题解,
align,
tnam,
offset,
now,
CSP
From: https://www.cnblogs.com/x383494/p/17780380.html