2020 浙江省赛(TeamVP)
比赛相关信息
比赛信息
比赛名称: The 17th Zhejiang Provincial Collegiate Programming Contest
比赛地址: GYM
比赛过程回顾
A | B | C | D | E | F | G | H | I | J | K | L | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
提交次数 | 1 | 1 | 1 | |||||||||
首次提交时间 | 02:04 | 01:52 | 00:20 | |||||||||
首A时间 | 02:04 | 01:54 | 00:20 | |||||||||
状态 | ✔ | ⚪ | ⚪ | ⚪ | ⚪ | ✔ | ✔ |
✔:比赛时通过;⚪:比赛时尝试过
部分题解与小结
A - AD 2020
小评
\(\mathcal{Solved\ by\ Wida\ \&\ Wcj\ \&\ Hwh}\)
稍有难度的打卡题。
题意
我们常用 \(\tt{}YYYYMMDD\) 来表示一个日期。现在,给出两个这种形式的日期,请你直接输出这两个日期之间包含 \(\tt{}202\) 的日期的数量。
思路
赛时思路(暴力打表与判断 + 离散化 + 前缀和预处理 + 差分)
很容易的想到前缀和预处理,难点在于怎么将八位的数字储存下来,理所当然的想到离散化辅助处理。
赛后优化
“离散”的计算日期 -> “连续”的计算日期 + 三维数组统计。这一步的好处在于可以跳过离散化这一步骤直接得到前缀和的下标。
使用 \(\tt{}if\) 语句判断 -> 使用循环语句判断。这一步的好处在于可以少推“年月日”与 \(\tt{}202\) 之间的关系。
AC代码
赛后优化
点击查看代码
//A WIDA Project
#include <bits/stdc++.h>
using namespace std;
const int N = 5e6 + 7;
int a[10000][13][32], s[N];
bool judge(int year, int month, int day) //判断这个日期中是否包含了 “202”
{
int x = year * 10000 + month * 100 + day;
while (x) {
if (x % 1000 == 202) return true;
x /= 10;
}
return false;
}
void Prepare() //预处理打表
{
int day[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int num = 0;
for (int Y = 2000; Y <= 9999; Y ++ ) {
day[2] = 28;
if ((Y % 4 == 0 && Y % 100 != 0) || (Y % 400 == 0)) day[2] = 29; //如果是闰年,更改 2 月份的天数
for (int M = 1; M <= 12; M ++ ) {
for (int D = 1; D <= day[M]; D ++ ) {
num ++ ;
a[Y][M][D] = num; //使用连续的方式 + 三维数组计算前缀和(替换原来的离散化步骤)
s[num] = s[num - 1] + judge(Y, M, D);
}
}
}
}
void solve()
{
int x1, x2, y1, y2, z1, z2; cin >> x1 >> y1 >> z1 >> x2 >> y2 >> z2;
cout << s[a[x2][y2][z2]] - s[a[x1][y1][z1] - 1] << endl;
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0);
Prepare();
int T; cin >> T;
while (T -- ) {
solve();
}
return 0;
}
C - Crossword Validation
小评
\(\mathcal{Solved\ by\ Wida (After)}\)
打卡水题。
赛时在还有两个小时的时候开了这题,当时以为很难( \(N*N\) 的矩阵查找,加上题目很长),于是就放弃了。赛后复盘时发现这题竟然是第二简单的打卡题,而且赛时题目读错导致想复杂了(以为对于任意在字典中出现过的字串都需要统计)几乎是一个裸的 \(\tt{}Trie\) 模板,于是赶紧补了一波字典树。
不过有一说一,这道题的题干是真的难读。
题意
给出一个矩阵,其中包含字母和符号 \(\#\) ,你需要从中取出所有能取到的最长串,然后查询其是否在给出的字典中,并计算权值和。
思路
将字典中的全部串依次取出建立字典树,再遍历矩阵依次找出所有的正确串并查找所建立的字典树即可。
AC代码
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define IOS() ios_base::sync_with_stdio(0);cin.tie(0);
#define LL long long
const int N =4e6+7;
int n, m;
char a[1010][1010];
int son[N][26], num[N], tot;
void Clear()
{
for (int i = 0; i <= tot; i ++ ) {
num[i] = 0;
for (int j = 0; j < 26; j ++ ) son[i][j] = 0;
}
tot = 0;
}
void insert(string s, int w)
{
int p = 0;
for (int i = 0; i < s.size(); i ++ ) {
int x = s[i] - 'a';
if(!son[p][x]) son[p][x] = ++ tot;
p = son[p][x];
}
num[p] = w;
}
int query(string s)
{
int p = 0;
for (int i = 0; i < s.size(); i ++ ) {
int x = s[i] - 'a';
if(!son[p][x]) return -1;
p = son[p][x];
}
if(num[p] == 0) return -1;
return num[p];
}
void Solve()
{
cin >> n >> m;
Clear();
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
cin >> a[i][j];
}
}
for (int i = 1; i <= m; i ++ ) {
string s; int w;
cin >> s >> w;
insert(s, w);
}
LL ans = 0; string str;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
if(a[i][j] != '#') str += a[i][j];
if(a[i][j] == '#' || j == n) {
if(str == "") continue;
int x = query(str);
if(x == -1) {
cout << -1 << endl;
return;
}
ans += x;
str = "";
}
}
}
for (int j = 1; j <= n; j ++ ) {
for (int i = 1; i <= n; i ++ ) {
if(a[i][j] != '#') str += a[i][j];
if(a[i][j] == '#' || i == n) {
if(str == "") continue;
int x = query(str);
if(x == -1) {
cout << -1 << endl;
return;
}
ans += x;
str = "";
}
}
}
cout << ans << endl;
}
int main()
{
IOS();
int Case; cin >> Case; while (Case -- > 0) {Solve();}
return 0;
}
I - Invoking the Magic
小评
\(\mathcal{Solved\ by\ Wcj\ \&\ Wida}\)
图论打卡题。
题意
有 \(k\) 种不同颜色的袜子,每种颜色两只。现在,它们被两两分成了 \(k\) 对,而你需要将它们分成正确的若干组,每组都会被重新配对。输出数量最多那个组的袜子对数。
思路
赛时思路(DFS划分连通块 + 离散化)
分到一组的袜子一定位于同一个连通块内,答案即为每个连通块包含点数的最大值。注意袜子颜色的数字较大,故需要进行离散化。
AC代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int n, v[N], cnt, ans;
vector<int> ver[N];
vector<pair<int, int> > query;
vector<int> alls;
map<int, int> mp;
void dfs(int x) {
v[x] = cnt;
for (auto y : ver[x]) {
if(v[y]) continue;
dfs(y);
}
}
int get(int x)
{
int l = 0, r = alls.size() - 1;
while(l < r) {
int mid = l + r >> 1;
if(alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1;
}
void add(int x, int y)
{
ver[x].push_back(y);
}
void solve()
{
cin >> n;
for (int i = 1; i <= n + 2; i ++) v[i] = 0, ver[i].clear();
cnt = 0; ans = 0;
alls.clear();
query.clear();
mp.clear();
for (int i = 1; i <= n ; i ++ ) {
int x, y;
cin >> x >> y;
query.push_back({x, y});
alls.push_back(x); //离散化数组
alls.push_back(y);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
for (auto i : query) {
int x = get(i.first), y = get(i.second);
add(x, y);
add(y, x);
}
for(int i = 1; i <= n; i ++) {
if(!v[i]) {
cnt ++;
dfs(i);
}
mp[v[i]] ++;
}
for (auto i : mp) ans = max(ans, i.second);
cout << ans << endl;
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0);
int T; cin >> T;
while(T -- ) {
solve();
}
return 0;
}
K - Killing the Brute-force
小评
\(\mathcal{Solved\ by\ Wida\ \&\ Hwh}\)
打卡水题
题意
思路
AC代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int a[N], b[N], flag;
void solve()
{
int n; cin >> n;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ ) cin >> b[i];
for (int i = 1; i <= n; i ++ ) {
if(a[i] * 3 < b[i]) {
flag = 1;
cout << i << endl;
break;
}
}
if(flag == 0) cout << -1 << endl;
}
void clear()
{
flag = 0;
}
int main()
{
int T; cin >> T;
while(T -- ) {
clear();
solve();
}
return 0;
}
文 / WIDA
2022 成文
首发于WIDA个人博客,仅供学习讨论
更新日记:
2022 成文