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 成文


posted @ 2022-02-26 20:31  hh2048  阅读(76)  评论(0编辑  收藏  举报