2021CCPC女生赛

这篇题解题目的顺序是按照我认为的难度顺序来的。

K.音乐游戏

  把每一行的字符串读进来之后,直接去计算这个字符串中有多少个""字符就可以了

int n; std::cin >> n; i64 ans = 0; rep(i,0,n + 1) { // for (int i = 0; i < n + 1; i ++ ) 读到n + 1的原因是getline读取字符串的时候好像会多读取一个空串进来 std::string s; std::getline(std::cin,s); ans += count(all(s), '-'); } std::cout << ans << "\n";

G.3G网络

  直接看样例的输入和输出可以猜出来,直接输出1n就可以了。

int n; std::cin >> n; std::cout << std::fixed << std::setprecision(20) << 1.0 / n << "\n";

  在输出的时候注意保留小数的位数,cout << 1.0 / n;会wa一发。

D.修建道路

  可能有些人觉得是最小生成树,但是这个题其实就是一个很简单的贪心,我们直接把原序列上相邻的两个点连边就可以了。

int n; std::cin >> n; std::vector<int> a(n + 1); for (int i = 1; i <= n; i ++ ) std::cin >> a[i]; i64 ans = 0; rep(i,1,n) ans += std::max(a[i], a[i + 1]); std::cout << ans << "\n";

A.公交线路

  我们从因为我们一开始并不能确定是往那边走,所以我们从起点开始,向前向后分别走m的长度,分别判断在这两种情况中是否坐错了,如果前后扫的时候都没有发现做错,那就输出Unsure

int n, x, y; std::cin >> n >> x >> y; std::vector<int> a(n + 1); rep(i,1,n + 1) std::cin >> a[i]; int m; std::cin >> m; std::vector<int> b(m + 1); rep(i,1,m + 1) std::cin >> b[i]; bool f = true, ff = true; for (int i = x - 1; i >= x - m; i -- ) { if (a[i] != b[x - i]) f = false; if (i == 0) break; } for (int i = x + 1; i <= x + m; i ++ ) { if (a[i] != b[i - x]) ff = false; } if (f && ff) std::cout << "Unsure\n"; else { if (f) std::cout << (x > y ? "Right\n" : "Wrong\n"); else if (ff) std::cout << (x > y ? "Wrong\n" : "Right\n"); }

I.驾驶卡丁车

  纯模拟题,注意读题判断细节就好了,一开始小丁车朝向是向上的,而且每一次操作的时候都要旋转45,所以为了操作方便,我们按照顺时针的方式建立方向数组。

int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};

每一次向前走v的长度的距离,在这个路上可能会遇上障碍,所以我们不能直接让小卡车直接过去,要for循环一点一点的走,每一步都要去判断,如果是斜着走的话两边不可以都是障碍。

int n, m; std::cin >> n >> m; std::vector<std::vector<char>> G(n + 1, std::vector<char> (m + 1)); int x = 0, y = 0; for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= m; j ++ ) { std::cin >> G[i][j]; if (G[i][j] == '*') x = i, y = j; } } int q; std::cin >> q; int v = 0; int cur = 0; std::string op; std::cin >> op; rep(i,0,q) { if (op[i] == 'U') v ++; if (op[i] == 'D') v = std::max(v - 1, 0); if (op[i] == 'L') cur = (cur - 1 + 8) % 8; if (op[i] == 'R') cur = (cur + 1) % 8; int nx, ny; bool flag = true; rep(xx, 0, v) { nx = x + dx[cur], ny = dy[cur] + y; if (nx < 1 || nx > n || ny < 1 || ny > m || G[nx][ny] == '#') { std::cout << "Crash! " << x << " " << y << "\n"; v = 0; flag = false; break; } if (cur == 1 || cur == 3 || cur == 5 || cur == 7) { if (G[x + dx[(cur - 1 + 8) % 8]][y + dy[(cur - 1 + 8) % 8]] == '#' && G[x + dx[(cur + 1) % 8]][y + dy[(cur + 1) % 8]] == '#') { std::cout << "Crash! " << x << " " << y << "\n"; v = 0; flag = false; break; } } x = nx, y = ny; } if (flag) std::cout << x << " " << y << "\n"; }

C.连锁商店

  有n个景点,m条缆线,每一个景点都会有一个连锁店,那些连锁店i都会有它们隶属的公司ci,并且连锁店会给游客红包wi元,不过每一个公司的红包只能拿一次.要求出从起点1开始都每一个景点能拿到的最大优惠红包是多少.
  到达每一个景点的方式是不固定的,也就是我们要枚举出所有的状态来找出从起点开始到达节点的最有路径是多少。枚举的方式就是采用状压dp的方式来用01表示能否到达。由于n的范围是1n36,这个范围非常大,开数组的话根本开不出236的空间,所以这里考虑用dp[i]来表示二进制下的状态,i就是当前的景点。那么从i走到k节点可能有很多条路,比如说ii+1jk 或者是ik但是我们并不知道那一条路能拿到最多的红包,所以我们考虑用Floyd算法来找到最优的路径,路经的景点越多拿到的红包才可能多,所以我们在Floyd的时候应该将直接到达的边删掉,这样不会影响我们后面枚举所有状态的过程。

for (int i = 1; i <= n; i ++ ) for (int j = 1; j <= n; j ++ ) for (int k = 1; k <= j; k ++ ) if ((path[i] & (1ll << j)) && (path[i] & (1ll << k)) && (path[k] & (1ll << j))) path[i] -= (1ll << j);

在状态转移的过程中,就有两种情况,一种是这个景点的公司的红包已经领过了那么状态转移方程就是dp[u]=dp[father], 另一种就是这个公司的红包没有拿过,那么状态转移方程就是dp[u]=dp[father]+w[c[u]],所以我们还需要一个数组来给景点的公司来打标记来确定最后的状态是什么

int n, m; std::cin >> n >> m; std::vector<int> c(n + 1), w(n + 1); std::vector<i64> path(n + 1); std::vector<i64> dp(n + 1); rep(i,1,n + 1) std::cin>>c[i]; rep(i,1,n + 1) std::cin>>w[i]; rep(i,0,m) { i64 u, v; std::cin >> u >> v; path[u] |= (1ll << v); } std::vector<int> vis(n + 1); std::vector<i64> ans(n + 1); std::function<void(int, int)> dfs = [&] (int u, int fa) -> void { if (!vis[c[u]]) dp[u] = dp[fa] + w[c[u]]; else dp[u] = dp[fa]; ans[u] = std::max(ans[u], dp[u]); vis[c[u]] ++; rep(i,1,n + 1) { if (path[u] & (1ll << i)) { dfs(i, u); vis[c[i]] --; } } }; rep(i,1,n + 1) rep(j,1,n + 1) rep(k,1,j + 1) if ((path[i] & (1ll << j)) && (path[i] & (1ll << k)) && (path[k] & (1ll << j))) path[i] -= (1ll << j); dfs(1, 0); rep(i,1,n + 1) std::cout << ans[i] << "\n";

F.地图压缩

  哈希一遍,然后将二维转化为一维之后,就是KMP直接找到行与列的最小循环节,最后的答案就是行与列最小循环节的长度的乘积

#include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 2009; const ll p = 1331; const ll mod = 998244353; int n, q; char mp[maxn][maxn]; ll col[maxn][maxn], row[maxn][maxn]; ll rcol[maxn][maxn], rrow[maxn][maxn]; ll mhuash[maxn]; ll rhuash[maxn]; ll s[maxn]; ll sr[maxn]; int nex[maxn]; int work(int len) { for(int i = 2, j = 0; i <= len; ++ i){ while (j && s[i] != s[j + 1]){ j = nex[j]; } if(s[i] == s[j + 1]){ ++ j; } nex[i] = j; } return len - nex[len]; } void pre(){ mhuash[0] = 1; for(int i = 1; i <= n; ++ i) mhuash[i] = mhuash[i - 1] * p % mod; for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= n; ++ j){ row[i][j] = (row[i][j - 1] * p + (mp[i][j] - 'a')) % mod; col[j][i] = (col[j][i - 1] * p + (mp[i][j] - 'a')) % mod; } } } int main(){ std::cin.tie(nullptr)->sync_with_stdio(false); cin >> n >> q; for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= n; ++ j){ cin >> mp[i][j]; } } pre(); while(q--){ int x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; for(int i = x1; i <= x2; ++ i) s[i - x1 + 1] = (row[i][y2] - row[i][y1 - 1] * mhuash[y2 - y1 + 1] % mod + mod) % mod; int len = x2 - x1 + 1; int ansx = work(len); for(int i = y1; i <= y2; ++ i) s[i - y1 + 1] = (col[i][x2] - col[i][x1 - 1] * mhuash[x2 - x1 + 1] % mod + mod) % mod; len = y2 - y1 + 1; int ansy = work(len); cout << ansx * ansy << "\n"; } }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16211162.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(226)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示