今天上午,2024CSP-J第二轮认证开始了。我筹备了一个多月,就是想在第一年拿个好成绩。
可是,就是这次考试,让我对CSP有了阴影。
本来今年我是第一次考,可是差点爆零!
先看看今年的题目:
不算是太难,但对于我这种小菜来说想要拿到150分是不可能的。我不确定我的代码是否正确,但也做出来第一题。
来跟大家分享一下我差点爆零的故事:
今天上午快11:30分时,监考人员说先把放在提交栏处的文件代码拷贝出来,以免丢失,因为他要清理提交记录。但我当时在看第四题,反正我也做不出来第四题,于是我就翘着二郎腿,开始摸鱼,根本没有听监考的话。于是,待我满怀信心回到提交处,发现我的代码不见了。我满脸惊慌,连忙向监考老师示意。虽然监考老师知道后有一万个不情愿,但还是帮我从清理的那堆垃圾中找到了我的代码。吓我一跳,我还以为我又要白手起家了。
今天下午,我的老师发了题解给我,来看看题解:
poker
#include <bits/stdc++.h>
using namespace std;
int n, ans, cnt[56 + 5], res;
int turn_1(char u)
{
if (u == 'D')
return 0;
if (u == 'C')
return 1;
if (u == 'H')
return 2;
if (u == 'S')
return 3;
}
int turn_2(char u)
{
if (u == 'A')
return 1;
if (u == 'T')
return 10;
if (u == 'J')
return 11;
if (u == 'Q')
return 12;
if (u == 'K')
return 13;
return u - '0';
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
string s;
cin >> s;
res = turn_1(s[0]) * 13 + turn_2(s[1]);
cnt[res]++;
}
for (int i = 1; i <= 52; i++)
if (!cnt[i])
ans++;
cout << ans;
return 0;
}
explore
#include <bits/stdc++.h>
#define N 1010
using namespace std;
int T, m, n, K, x, y, d;
int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
char mm[N][N];
bool vis[N][N];
bool ok(int u, int v) // 判断位置(u,v)是否合法
{
if (u < 1 || u > m || v < 1 || v > n)
return 0;
if (mm[u][v] != '.')
return 0;
return 1;
}
int main()
{
cin >> T;
while (T--)
{
memset(vis, 0, sizeof(vis));
scanf("%d%d%d", &m, &n, &K);
scanf("%d%d%d", &x, &y, &d);
for (int i = 1; i <= m; i++)
scanf("%s", mm[i] + 1);
vis[x][y] = 1;
while (K--)
{
int nx, ny;
nx = x + dir[d][0];
ny = y + dir[d][1];
if (!ok(nx, ny))
{
d = (d + 1) % 4;
continue;
}
x = nx, y = ny;
vis[x][y] = 1;
}
int ans = 0;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (vis[i][j])
ans++;
printf("%d\n", ans);
}
}
sticks
#include <bits/stdc++.h>
using namespace std;
int T, n, len;
int cnt[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
bool judge(int u, int v) // 判断用v个火柴棒拼成u个数位是否合法
{
if (v > u * 7)
return 0;
if (v < u * 2)
return 0;
return 1;
}
void work(int now, int sum) // 目前在填第now位,火柴棒还有sum个
{
if (!now)
return;
int st = 0;
if (now == len) // 注意不能有前导零
st = 1;
for (int i = st; i <= 9; i++) // 尝试将i填到第now位
{
if (judge(now - 1, sum - cnt[i]))
{
printf("%d", i);
work(now - 1, sum - cnt[i]);
break;
}
}
}
int main()
{
cin >> T;
while (T--)
{
scanf("%d", &n);
if (n == 1)
{
puts("-1");
continue;
}
len = (n + 6) / 7; // 计算最终的数位个数
work(len, n);
puts("");
}
return 0;
}
chain
#include <bits/stdc++.h>
#define N 200100
#define M 110
using namespace std;
int T, n, K, Q, ok[M][N];
vector<int> num[N];
int main()
{
cin >> T;
while (T--)
{
memset(ok, -1, sizeof(ok));
scanf("%d%d%d", &n, &K, &Q);
for (int i = 1; i <= n; i++)
{
num[i].clear();
int len;
scanf("%d", &len);
for (int j = 1; j <= len; j++)
{
int t;
scanf("%d", &t);
num[i].push_back(t);
}
}
ok[0][1] = 0;
for (int T = 1; T <= 100; T++)
{
for (int i = 1; i <= n; i++)
{
int len = 0;
for (auto t : num[i])
{
len = max(len - 1, 0);
if (len)
{
if (ok[T][t] == -1)
ok[T][t] = i;
else if (ok[T][t] && ok[T][t] != i)
ok[T][t] = 0;
}
if (ok[T - 1][t] != -1 && ok[T - 1][t] != i)
len = K;
}
}
}
while (Q--)
{
int p, q;
scanf("%d%d", &p, &q);
puts(ok[p][q] != -1 ? "1" : "0");
}
}
}
我认为,poker用字符串去重,explore用深搜,sticks用暴力枚举+找规律,chain用链表+动态规划。可是,我有一个同学第一题用了set函数,直接把我震撼到了。
首先先定义一个set函数,输入一个字符串就存进去一个,因为set函数会自动去重,所以不必要再判断重复,最后用52减去set函数中的数就行了。
我用了一点小暴力,但是放手一搏的感觉真爽(我实在做不出来,到11:30了才被迫用这个方案的)。虽然我是放手一搏,但过了我的很多样例。什么实力我不说!
总之,第一次考CSP-J复赛还是很惊险的,虽然旁边就是大佬,但看不到大佬的代码呀!