P9754 [CSP-S 2023] 结构体
题面
说几个坑点,一定要看提示,要不然题目感觉不是很能理解出题人的意思。
看了提示要注意到时 \(a_i\) 的倍数,而不是所有 \(a\) 的最大值。
并要注意到他按顺序排列也是要遵守对齐规则的。
思路
思路很简单,就是把所有结构体存下来,然后按照他给的公式算大小和对齐值。
然后再加入的时候先把他放进去,等后面再来一个元素时,根据公式算出这个元素的起始位置,然后减去上一个地址,得到上一个元素的大小。
在查询元素的起始位置时,就暴力的每次进去一维算一下前缀和即可。
在查询位置的元素时,就是算前缀和和当前位置比大小就好了。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int long long
vector<vector<string>> g, gx; // 名字 类型名
vector<vector<ll>> len; // 长度
map<string, ll> mp, dyc, lenn;
ll inn;
string nm[105];
string lxnm[105];
ll dx[105];
int ntt;
ll nadd, lstlen;
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
int _;
cin >> _;
dyc["byte"] = 1;
dyc["short"] = 2;
dyc["int"] = 4;
dyc["long"] = 8;
lenn["byte"] = 1;
lenn["short"] = 2;
lenn["int"] = 4;
lenn["long"] = 8;
while (_--)
{
int op;
cin >> op;
// cout << op << " ";
if (op == 1)
{
string lxm;
cin >> lxm;
ll k;
cin >> k;
mp[lxm] = ntt++;
vector<string> mz, lx;
vector<ll> lz;
ll mx = 0, tlen = 0;
ll tot = 0, lst = 0;
for (int i = 1; i <= k; i++)
{
string lm, s;
cin >> lm >> s;
if (i > 1)
{
tot = (tot + lst + dyc[lm] - 1) / dyc[lm] * dyc[lm];
}
mz.push_back(s);
lz.push_back(lenn[lm]);
lx.push_back(lm);
tlen += lenn[lm];
mx = max(mx, dyc[lm]);
lst = lenn[lm];
}
g.push_back(mz);
gx.push_back(lx);
len.push_back(lz);
dyc[lxm] = mx;
lenn[lxm] = (tot + lst + mx - 1) / mx * mx;
cout << lenn[lxm] << " " << mx << "\n";
}
else if (op == 2)
{
cin >> lxnm[inn];
cin >> nm[inn];
ll le = lenn[lxnm[inn]];
ll lstadd = nadd;
nadd -= lstlen;
if (inn)
{
nadd = (nadd + lstlen + dyc[lxnm[inn]] - 1) / dyc[lxnm[inn]] * dyc[lxnm[inn]];
dx[inn] = le;
dx[inn - 1] += nadd - lstadd;
}
else
{
dx[inn] = le;
}
cout << nadd << "\n";
nadd += le;
lstlen = le;
inn++;
}
else if (op == 3)
{
string s;
cin >> s;
int i = 0;
string nw = "";
while (i < s.size() && s[i] != '.')
{
nw += s[i];
i++;
}
i++;
string lxm;
ll ans = 0;
for (int j = 0; j < inn; j++)
{
if (nm[j] == nw)
{
lxm = lxnm[j];
break;
}
ans += dx[j];
}
for (; i < s.size(); i++)
{
ll nmx = dyc[lxm];
ll nid = mp[lxm];
string nw = "";
while (i < s.size() && s[i] != '.')
{
nw += s[i];
i++;
}
ll tot = 0, lst = 0;
for (int j = 0; j < g[nid].size(); j++)
{
if (j)
{
tot = (tot + lst + dyc[gx[nid][j]] - 1) / dyc[gx[nid][j]] * dyc[gx[nid][j]];
}
if (g[nid][j] == nw)
{
ans += tot;
lxm = gx[nid][j];
break;
}
lst = lenn[gx[nid][j]];
}
// cout << nw << " " << ans << "\n";
}
cout << ans << "\n";
}
else
{
ll x;
cin >> x;
if (x >= nadd)
{
cout << "ERR\n";
continue;
}
string ans = "";
string lxm;
for (int j = 0; j < inn; j++)
{
// cout << dx[j] << "\n";
if (x < dx[j])
{
lxm = lxnm[j];
ans += nm[j];
break;
}
x -= dx[j];
}
while (1)
{
if (lxm == "byte" || lxm == "int" || lxm == "short" || lxm == "long")
{
if (x >= dyc[lxm])
{
ans = "ERR";
}
break;
}
// cout << x << "\n";
ll nmx = dyc[lxm];
ll nid = mp[lxm];
bool flg = 0;
ll tot = 0, lst = 0, lsttot = 0;
for (int j = 0; j < g[nid].size(); j++)
{
if (j)
{
tot = (tot + lst + dyc[gx[nid][j]] - 1) / dyc[gx[nid][j]] * dyc[gx[nid][j]];
}
// cout << "*" << tot << "\n";
if (x < tot)
{
lxm = gx[nid][j - 1];
ans += ".";
ans += g[nid][j - 1];
flg = 1;
x -= lsttot;
break;
}
lst = lenn[gx[nid][j]];
lsttot = tot;
}
if (!flg)
{
tot = (tot + lst + dyc[lxm] - 1) / dyc[lxm] * dyc[lxm];
// cout << "*" << tot << "\n";
if (x <= tot)
{
lxm = gx[nid][g[nid].size() - 1];
ans += ".";
ans += g[nid][g[nid].size() - 1];
flg = 1;
x -= lsttot;
}
}
// cout << "*" << ans << "\n";
if (!flg)
{
ans = "ERR";
break;
}
}
cout << ans << "\n";
}
}
return 0;
}
总结
先好好读题(读完,说不定出题人写了提示呢)。
注意每道题的边界情况,别把代码写出来后再去想边界。

浙公网安备 33010602011771号