CSP-S 2023 题解
CSP-S 2023 题解
T1 密码锁
观察到锁的状态数量很少,可以考虑暴力搜索每一个状态判断合法性。令
code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int kmax = 15;
struct V {
int a[6];
} v[kmax];
int n;
int res;
int p[kmax];
bool C(int id) {
int tot = 0;
for(int i = 1; i <= 5; i++) {
tot += (p[i] == v[id].a[i]);
}
if(tot == 5) return 0; // 完全相同
if(tot == 4) return 1; // 只有一个不同
if(tot < 3) return 0; // 超过两个不同
for(int i = 1; i < 5; i++) { // 枚举相同的两位
if(p[i] != v[id].a[i] && p[i + 1] != v[id].a[i + 1]) {
int x = (p[i] + 1) % 10, y = (p[i + 1] + 1) % 10;
for(; x != p[i]; x = (x + 1) % 10, y = (y + 1) % 10) { // 暴力枚举变化量
if(x == v[id].a[i] && y == v[id].a[i + 1]) return 1;
}
}
}
return 0;
}
bool Check() {
for(int i = 1; i <= n; i++) {
if(!C(i)) return 0;
}
return 1;
}
void Dfs(int x) {
if(x > 5) {
res += Check();
return;
}
for(int i = 0; i < 10; i++) {
p[x] = i;
Dfs(x + 1);
}
}
int main() {
// freopen("lock.in", "r", stdin);
// freopen("lock.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= 5; j++) {
cin >> v[i].a[j];
}
}
Dfs(1); // 暴搜
cout << res << '\n';
return 0;
}
T2 消消乐
考虑dp。定义
考虑优化,重新定义
常数还是有点大,发现瓶颈在于要枚举每种字符。发现跳
code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int kmax = 2e6 + 3;
const int kmaxM = 26;
int n, a[kmax][kmaxM], f[kmax];
int lst[kmax];
string str;
long long res;
int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
cin >> n >> str;
str = ' ' + str;
for(int i = 1; i <= n; i++) {
lst[i] = i;
int pre = a[lst[i - 1]][str[i] - 'a']; // 取出匹配的位置
if(pre) {
// cout << "***\n";
lst[i] = lst[pre - 1]; // 修改链头
f[i] = f[pre - 1] + 1; // 计算贡献
}
a[lst[i]][str[i] - 'a'] = i;
res += f[i];
}
cout << res << '\n';
return 0;
}
T3 结构体
大模拟,比较麻烦。对于每个结构体,需要存储它的变量数量、所有变量类型及名称、每个变量的对齐要求和地址偏移量,结构体的长度和该结构体的对齐要求。对于每个变量,存储它的起始位置、长度、对齐要求、类型、名字。为方便处理,要开两个 std::map
记录每个定义的结构体/变量的编号。初始时只有
定义一个结构体时,根据题面提示中给定的结构体地址分配方式计算当前结构体的长度、对齐要求,以及结构体中每一个变量的地址偏移量。
定义一个变量时,它的长度和对其方式与该变量类型的长度和对齐方式相同,只需要按照题意根据上一个变量的起始位置和长度来求出当前变量的起始位置。
访问一个变量的起始位置时,不断地将字符串中的变量名称拎出来,这样可以定位到每一个结构体内的哪一个变量及它的类型。注意第一次是全局变量名称,然后才是结构体中的变量名称,要分开处理。每一个结构体/变量的名称长度
查询每一个位置是由哪一个变量占据时,先二分求出它是在哪一个全局变量内,然后不断递归,每一层也同样二分出在哪一个变量内。如果在某一层内发现询问的位置上是空的,就可以返回无解了。注意在最底层,即到了基本类型的时候,虽然不用往下递归了,但依然要判断询问的位置是否被占据。如果有解,用一个栈维护变量的名称,每次返回的时候将变量的名称弹入栈中。
code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
const int kmax = 105;
struct Strct {
int num;
string tpe[kmax];
string nam[kmax];
long long o[kmax], a[kmax];
long long len, mx;
} strcc[kmax];
struct Chg {
long long beg, len, mx;
string tpe, nam;
} chage[kmax];
map<string, int> sct, chg;
int n, ct, ctt;
int tp;
string str, strr;
string resstr[kmax];
void Addstr() {
cin >> str;
sct[str] = ++ct;
cin >> strcc[ct].num;
for(int i = 1; i <= strcc[ct].num; i++) {
cin >> strcc[ct].tpe[i] >> strcc[ct].nam[i];
int x = sct[strcc[ct].tpe[i]];
strcc[ct].mx = max(strcc[ct].mx, strcc[x].mx);
if(i > 1) {
long long lst = strcc[ct].o[i - 1] + strcc[sct[strcc[ct].tpe[i - 1]]].len;
if(lst % strcc[x].mx == 0) {
strcc[ct].o[i] = lst;
} else {
strcc[ct].o[i] = (lst / strcc[x].mx + 1) * strcc[x].mx;
}
}
}
long long lst = strcc[ct].o[strcc[ct].num] + strcc[sct[strcc[ct].tpe[strcc[ct].num]]].len;
if(lst % strcc[ct].mx == 0) {
strcc[ct].len = lst;
} else {
strcc[ct].len = (lst / strcc[ct].mx + 1) * strcc[ct].mx;
}
cout << strcc[ct].len << ' ' << strcc[ct].mx << '\n';
}
void Addchg() {
cin >> str >> strr;
chg[strr] = ++ctt;
chage[ctt].tpe = str;
chage[ctt].mx = strcc[sct[str]].mx;
chage[ctt].len = strcc[sct[str]].len;
chage[ctt].nam = strr;
if(ctt > 1) {
long long lst = chage[ctt - 1].beg + chage[ctt - 1].len;
if(lst % chage[ctt].mx == 0) {
chage[ctt].beg = lst;
} else {
chage[ctt].beg = (lst / chage[ctt].mx + 1) * chage[ctt].mx;
}
}
cout << chage[ctt].beg << '\n';
}
void Findbeg() {
cin >> str;
long long res = 0;
long long lst;
for(int i = 0, j = 0; i < (int)str.size(); i = ++j) {
for(; j < (int)str.size() && str[j] != '.'; j++) {
}
// cout << str.substr(i, j - i) << '\n';
if(i == 0) {
res = chage[chg[str.substr(i, j - i)]].beg;
lst = sct[chage[chg[str.substr(i, j - i)]].tpe];
} else {
for(int k = 1; k <= strcc[lst].num; k++) {
if(strcc[lst].nam[k] == str.substr(i, j - i)) {
res += strcc[lst].o[k];
lst = sct[strcc[lst].tpe[k]];
}
}
}
}
cout << res << '\n';
}
bool Dfs(long long pos, long long lst) {
if(lst == -1) {
int l = 1, r = ctt;
for(int mid; l <= r;) {
mid = (l + r) >> 1;
if(chage[mid].beg <= pos) {
l = mid + 1;
} else {
r = mid - 1;
}
}
int res = l - 1;
if(res == 0) {
resstr[++tp] = "ERR";
return 0;
}
if(chage[res].beg + chage[res].len < pos) {
resstr[++tp] = "ERR";
return 0;
}
if(!Dfs(pos - chage[res].beg, sct[chage[res].tpe])) return 0;
resstr[++tp] = chage[res].nam;
return 1;
}
// cout << "lst = " << lst << ' ' << pos << '\n';
if(!strcc[lst].num) {
if(lst <= 4 && pos < strcc[lst].len) {
// cout << "lst = " << lst << ' ' << strcc[lst].len << ' ' << strcc[lst].mx << '\n';
return 1;
} else {
resstr[++tp] = "ERR";
return 0;
}
}
int l = 1, r = strcc[lst].num;
for(int mid; l <= r;) {
mid = (l + r) >> 1;
if(strcc[lst].o[mid] <= pos) {
l = mid + 1;
} else {
r = mid - 1;
}
}
int res = l - 1;
if(!res) {
resstr[++tp] = "ERR";
return 0;
}
if(strcc[lst].o[res] + strcc[sct[strcc[lst].tpe[res]]].len < pos) {
resstr[++tp] = "ERR";
return 0;
}
if(!Dfs(pos - strcc[lst].o[res], sct[strcc[lst].tpe[res]])) return 0;
// cout << "str = " << strcc[lst].nam[res] << '\n';
resstr[++tp] = strcc[lst].nam[res];
return 1;
}
void Findpos() {
long long pos;
cin >> pos;
tp = 0;
Dfs(pos, -1);
cout << resstr[tp--];
for(; tp; tp--) {
cout << '.' << resstr[tp];
}
cout << '\n';
}
int main() {
freopen("struct.in", "r", stdin);
freopen("struct.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
sct["byte"] = ++ct, strcc[ct].len = strcc[ct].mx = 1;
sct["short"] = ++ct, strcc[ct].len = strcc[ct].mx = 2;
sct["int"] = ++ct, strcc[ct].len = strcc[ct].mx = 4;
sct["long"] = ++ct, strcc[ct].len = strcc[ct].mx = 8;
cin >> n;
for(int i = 1, op; i <= n; i++) {
cin >> op;
if(op == 1) {
Addstr();
} else if(op == 2) {
Addchg();
} else if(op == 3) {
Findbeg();
} else {
Findpos();
}
}
return 0;
}
T4 种树
答案显然满足单调性,可以先二分出答案。
假设二分出的答案为
同时,
最后将
时间复杂度
code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int kmax = 1e5 + 3;
struct Tree {
long long a;
int b, c;
int d;
} tr[kmax];
struct E {
int p, y;
} e[kmax << 1];
int n;
int h[kmax], ec;
int f[kmax];
int l[kmax];
bool b[kmax];
void Dfs(int x, int fa) {
for(int i = h[x]; i; i = e[i].p) {
int y = e[i].y;
if(y == fa) continue;
Dfs(y, x);
l[x] = min(l[x], l[y] - 1);
}
}
__int128 Calc(int id, __int128 lst) {
if(tr[id].c >= 0) return lst * tr[id].b + lst * (lst + 1) / 2 * tr[id].c;
__int128 rs = (1 - tr[id].b) / tr[id].c;
if(lst <= rs) return lst * tr[id].b + lst * (lst + 1) / 2 * tr[id].c;
return rs * tr[id].b + rs * (rs + 1) / 2 * tr[id].c + lst - rs;
}
int Pos(int id, long long k) {
int l = 1, r = n;
__int128 ps = Calc(id, k);
for(int mid; l <= r;) {
mid = (l + r) >> 1;
if(ps - Calc(id, mid - 1) >= tr[id].a) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return l - 1;
}
bool Check(long long k) {
for(int i = 1; i <= n; i++) {
if(Calc(i, k) < tr[i].a) return 0;
l[i] = Pos(i, k);
}
Dfs(1, 0);
sort(l + 1, l + n + 1);
for(int i = 1; i <= n; i++) {
if(l[i] < i) return 0;
}
return 1;
}
void Addedge(int x, int y) {
e[++ec] = {h[x], y};
h[x] = ec;
}
int main() {
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> tr[i].a >> tr[i].b >> tr[i].c;
}
for(int i = 1, x, y; i < n; i++) {
cin >> x >> y;
Addedge(x, y);
Addedge(y, x);
}
long long l = n, r = 1e9;
for(long long mid; l <= r;) {
mid = (l + r) >> 1;
if(Check(mid)) {
r = mid - 1;
} else {
l = mid + 1;
}
}
cout << r + 1 << '\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效