2023年江苏省赛和湖南CCPC题解
I. Elevator
题意:电梯中有n个人,m个人选择互不相同的楼层离开,问最多有多少人在同一层离开。
题解:输出 \(n-m+1\)
点击查看代码
void slove()
{
int n, m; cin >> n >> m;
cout << n - m + 1 << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) slove();
return 0;
}
J. Similarity (Easy Version)
题意:给定n个字符串,输出两个字符串的最长公共子串的长度。\(2\leq n\leq300,1\leq|s|\leq50\)
题解:枚举每两个字符串,求出最长公共子串即可。\(O(n^2 * |s|^2)\)
PS:子串是连续的,注意和子序列区分
点击查看代码
int LCS(string s1, string s2) {
int n = s1.size(), m = s2.size();
s1 = " " + s1;
s2 = " " + s2;
vector f(n + 5, vector<int>(m + 5));
int res = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s1[i] == s2[j]) f[i][j] = f[i - 1][j - 1] + 1;
res = max(res, f[i][j]);
}
}
return res;
}
void slove()
{
int n; cin >> n;
vector<string> a(n + 5);
for (int i = 1; i <= n; i++) cin >> a[i];
int res = 0;
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
res = max(res, LCS(a[i], a[j]));
}
}
cout << res << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) slove();
return 0;
}
H. Neil's Machine
题意:给定两个长度为N的字符串,文本串S和目标串T,操作为:可以对文本串S的任意后缀将其偏移K位。\(1\leq K\leq25\)。求最小的操作次数使得S和T匹配。\(1\leq N\leq2e5\)
题解:遍历S,统计偏移量,如果当前位置偏移的字符和T不同,选择累加操作1次,将其偏移为相同的字符,并累加偏移量。\(O(N)\)
点击查看代码
char cal(char c, int cnt) {
int t = ((c - 'a' + cnt) % 26 + 26) % 26; // 偏移量可能为负数
char res = (char)('a' + t);
return res;
}
void slove()
{
int n; cin >> n;
string s, t; cin >> s >> t;
int res = 0, sum = 0;
for (int i = 0; i < n; i++) {
char c = cal(t[i], sum);
if (s[i] == c) continue;
sum += s[i] - c;
res++;
}
cout << res << endl;
}
A. Today's Word
题意:给定一个长度为N(偶数)的字符串S,每次将这个字符串的前一半子串拼接在前面,再将后一半子串计算next(suf)拼接在后面(next操作就是对每个字符在字母表中往后偏移一次)。重复1e100次操作,求最后的字符串长度为M的后缀。\(1\leq N\leq1e5,1\leq M \leq1e5\)
题解:N需要为偶数,最小为2,S的后一半suf最小长度为1,每次扩展一倍。1e100次就是扩大 \(2^{1e100}\) 倍。suf拼接完成之后,最小长度也是大于M的,所以无需关系S的前一半子串。\(1e100\ mod \ 26 = 16\) ,对于suf可以计算出next 1e100 次之后的字符串。再往前面递推,直到递推出长度超过M即可停止。
最多往前递推几次呢?17次,\(2^{17}\) 就已经超过1e5长度了。
为什么得到最后的suf,在往前依次递推即可?上标表示next的次数
正推三次:\(suf->suf+suf^1->suf+suf^1+suf^1+suf^2->suf+suf^1+suf^1+suf^2+suf^1+suf^2+suf^2+suf^3\)
倒推三次:\(suf^3->suf^2+suf^3->suf^1+suf^2+suf^2+suf^3->suf+suf^1+suf^1+suf^2+suf^1+suf^2+suf^2+suf^3\)
倒退就是每次往前拼接偏移量为-1的子串。
点击查看代码
int cnt = 16;
char cal(char c) {
int t = ((c - 'a' + cnt) % 26 + 26) % 26;
char res = (char) t + 'a';
return res;
}
string dfs(string s) {
for (int i = 0; i < s.size(); i++) {
s[i] = cal(s[i]);
}
return s;
}
void slove()
{
int n, m; cin >> n >> m;
string s; cin >> s;
string suf = s.substr(n / 2, n / 2);
suf = dfs(suf);
cnt = -1;
for (int i = 1; i <= 26; i++) {
if (suf.size() >= m) break;
suf = dfs(suf) + suf;
}
string res;
res.resize(m);
int idx = 0;
for (int i = suf.size() - 1; idx < m; i--) {
res[idx++] = suf[i];
}
for (int i = m - 1; i >= 0; i--) cout << res[i];
cout << endl;
}
K. Similarity (Hard Version)
题意:要求构造出N个互不相同的长度为K的字符串,要求最长公共子串的长度为M。如果不能构造输出No 。\(2\leq N\leq 300, 0\leq M\leq50,1\leq K\leq 100\)
题解:首先判断什么情况不能构造,当 \(K\leq M\) ,不能构造出互不相同的。当 \(M=0\) 时,\(N > 26\) 。要求N个字符串互相没有相同的部分,最多只能构造26个
如何构造:首先构造出相同的M长度,比如 \(M=3\) ,aaa 然后可以拼接不同的字符,达到互不相同的目的。aaabaaabaaa、aaacaaacaaa 。
一个变量控制公共部分,一个变量控制不同。最多可以构造出 26+25+24+.......+1 = 351 个字符。
点击查看代码
void slove()
{
int n, m, k; cin >> n >> m >> k;
if (k <= m || (m == 0 && n > 26)) {
cout << "No" << endl;
return;
}
int x = 0; int y = 0;
int cnt = 1;
vector<string> res(n);
for (int i = 0; i < n; i++) {
string s; s.resize(k);
int idx = 0;
while (idx < k) {
for (int j = 1; j <= m && idx < k; j++) {
s[idx++] = 'a' + x;
}
if (idx < k) s[idx++] = 'a' + y;
}
res[i] = s;
y++;
if (y == 26) {
x++;
y = cnt;
cnt++;
}
}
cout << "Yes" << endl;
for (int i = 0; i < n; i++) cout << res[i] << endl;
}
L. Architect
题意:有一个大的长方体,坐标从(0, 0, 0) 到 (W, H, L) 。现在有 N 个小长方体,判断这些小长方体是否可以将大长方体填满,并且不重叠。\(1\leq N\leq 3e5, 1\leq W,H,L\leq1e9\)
题解:三维差分,每次对于小长方体记录区域贡献+1,最后对整个区域-1,判断最后贡献是否全为0.
点击查看代码
int n, x, y, z;
struct node {
int _1, _2, _3;
bool operator < (const node& e2) const {
if (_1 != e2._1) return _1 < e2._1;
if (_2 != e2._2) return _2 < e2._2;
return _3 < e2._3; // 这里不能取等号
}
};
map<node, int> d;
void cal(int x1, int y1, int z1, int x2, int y2, int z2, int c) {
d[{x1, y1, z1}] += c;
d[{x2 + 1, y1, z1}] -= c;
d[{x1, y1, z2 + 1}] -= c;
d[{x2 + 1, y1, z2 + 1}] += c;
d[{x1, y2 + 1, z1}] -= c;
d[{x2 + 1, y2 + 1, z1}] += c;
d[{x1, y2 + 1, z2 + 1}] += c;
d[{x2 + 1, y2 + 1, z2 + 1}] -= c;
}
void slove()
{
cin >> x >> y >> z >> n;
while (n--) {
int x1, y1, z1, x2, y2, z2; cin >> x1 >> y1 >> z1 >> x2 >> y2 >> z2;
cal(x1, y1, z1, x2 - 1, y2 - 1, z2 - 1, 1);
}
cal(0, 0, 0, x - 1, y - 1, z - 1, -1);
bool flg = true;
for (auto &[t, v] : d) {
if (v != 0) {
flg = false;
break;
}
}
if (flg) cout << "Yes" << endl;
else cout << "No" << endl;
d.clear();
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) slove();
return 0;
}
浙公网安备 33010602011771号