The 2023 Guangdong Provincial Collegiate Programming Contest

1|0A - 算法竞赛


#include <bits/stdc++.h> using namespace std; #define int long long void solve(){ int st , n , ed; cin >> st >> n; map<int,int> cnt; for( int i = 1 , x ; i <= n ; i ++ ){ cin >> x; cnt[x] ++; } cin >> ed; int res = 0; for( int i = st ; i <= ed ; i ++ ){ if( cnt[i] ) continue; res ++; } cout << res << "\n"; return ; } int32_t main() { int t; cin >> t; for( ; t ; t -- ){ solve(); } return 0; }

2|0B - 基站建设


f(i)表示前i个基站i必选的情况下的最小成本f(i)=minf(j)+ai

注意[j+1,i1]中不能有任何一个完整区间,所以我们要计算出lim(i)表示[lim(i),i]中没有完整区间的最小值。那么jlim(i1)1

然后再用单调队列优化一下dp

#include <bits/stdc++.h> using namespace std; #define int long long void solve() { int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; i++) cin >> a[i]; // 在 n+1 添加一个花费为 0 的基站,并添加一个 [n+1,n+1] 的需求区间这样 f[n+1] 就是答案 a.push_back(0), n++; int m; cin >> m; vector<vector<int>> b(n+1); // 里面的负数 -j 表示有一个需求区间是 [i, j] // 里面是正数 j 表示有一个需求区间是 [j, i] for (int i = 1, l, r; i <= m; i++) cin >> l >> r, b[l].push_back(-r), b[r].push_back(l); b[n].push_back( -n) ,b[n].push_back(n); vector<int> lim(n+1); for( int l = 1 , r = 1 , cnt = 0; l <= n ; r ++ ){ for( auto x : b[r] ) if( x > 0 && x >= l ) cnt ++; while( cnt > 0 && l <= r ){ for( auto x : b[l] ) if( x < 0 && -x <= r ) cnt --; l ++; } lim[r] = l; } vector<int> f( n+1 ); deque<int> q; f[1] = a[1] , q.push_back(0) , q.push_back(1); for( int r = 2 , l ; r <= n ; r ++ ){ l = lim[r-1] - 1; while( q.front() < l ) q.pop_front(); f[r] = f[ q.front() ] + a[r]; while( !q.empty() && f[ q.back() ] >= f[r] ) q.pop_back(); q.push_back(r); } cout << f[n] << "\n"; } int32_t main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int t; cin >> t; for (; t; t--) solve(); return 0; }

3|0C - 市场交易


按照价格排序后贪心购买

#include <bits/stdc++.h> using namespace std; #define int long long void solve(){ int n; cin >> n; vector<pair<int,int>> a(n); for( auto & [x , y ] : a ) cin >> x >> y; sort( a.begin(), a.end() ); int res = 0; for( int l = 0 , r = n-1 , t ; l < r ; ){ t = min( a[l].second , a[r].second ); res += (a[r].first - a[l].first) * t; a[l].second -= t , a[r].second -= t; if( a[l].second == 0 ) l ++; if( a[r].second == 0 ) r --; } cout << res << "\n"; return ; } int32_t main() { ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr); int t; cin >> t; for( ; t ; t -- ){ solve(); } return 0; }

4|0D - 新居规划


把人按照aibi从小到大排序,排序后越靠前的人越喜欢独居,越靠后的人越喜欢群居,然后分别计算前缀独居贡献和和后缀群居贡献和。最后枚举出独居的人数即可。

#include <bits/stdc++.h> using namespace std; #define int long long void solve(){ int n , m; cin >> n >> m; vector<pair<int,int>> a(n); for( auto &[x,y] : a ) cin >> x >> y; sort( a.begin(), a.end() , [](pair<int,int> x , pair<int,int>y){ return x.first-x.second < y.first - y.second; } ); vector<int> p(n+1) , q(n+1); for( int i = 1 ; i <= n ; i ++ ) p[i] = p[i-1] + a[i-1].second; q[n] = a[n-1].first; for( int i = n-1 ; i >= 1 ; i -- ) q[i] = q[i+1] + a[i-1].first; reverse(q.begin()+1, q.end()); int res = 0; for( int i = 0 , j = n ; i <= n ; i ++ , j -- ){ if( i * 2 + j > m ) break; if( j < 2 ) continue; res = max( res , p[i] + q[j] ); } if( 2 * n - 1 <= m ) res = max( res , p[n] ); cout << res << "\n"; return ; } int32_t main() { ios::sync_with_stdio(false) , cin.tie(nullptr) , cout.tie(nullptr); int t; cin >> t; for( ; t ; t -- ){ solve(); } return 0; }

5|0E - 新杯质问


把所有的字符串都插入到 Tire 上,然后贪心的选择即可,首先给每个分支都任一选择一个,这样的话 LCP不会变化。如果不能满足选择的需求的话,就按照字典序贪心的选择,最后一个选到的就是 LCP 新增的一位。

#include <bits/stdc++.h> using namespace std; #define int long long vector<int> val; struct node { vector<int> to; int g, cnt; node() { to = vector<int>(26, -1); cnt = 0, g = -1; } }; vector<node> tire; string res; void dfs(int x) { if (tire[x].cnt) val[x] = tire[x].cnt; for (auto y: tire[x].to) { if (y == -1) continue; dfs(y); val[x] += val[y]; } return; } void calc(int x, int k) { if (tire[x].g != -1) res += (char) (tire[x].g + 'a'); if( tire[x].cnt ) k -= tire[x].cnt; if( k <= 1 ) return ; int cnt = 26; for (auto y: tire[x].to) cnt -= (y == -1); if (cnt >= k) return; for (auto y: tire[x].to) { if (y == -1) continue; cnt--; if (cnt + val[y] < k) k -= val[y]; else { k -= cnt; calc(y, k); return; } } } void solve() { int n, m; cin >> n >> m; tire = vector<node>(1, node()); for (int i = 1, t; i <= n; i++) { string s; cin >> s; t = 0; for (int i = 0, j; i < s.size(); i++) { j = s[i] - 'a'; if (tire[t].to[j] == -1) { tire[t].to[j] = tire.size(); tire.push_back(node()); tire.back().g = j; } t = tire[t].to[j]; } tire[t].cnt ++; } val = vector<int>(tire.size()); dfs(0); res = ""; calc(0, m); if (res == "") res = "EMPTY"; cout << res << "\n"; } int32_t main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int t; cin >> t; for (; t; t--) { solve(); } return 0; }

6|0I - 路径规划


二分答案,二分mex的值,则[0,mex1]都应该在序列中,这样这些点的下标按照x升序排列后,y也应该是升序排序。所以O(nlogn)的校验即可

#include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; vector<pair<int, int>> a(n * m); for( int i = 1 ; i <= n ; i ++ ) for( int x , j = 1 ; j <= m ; j ++ ) cin >> x , a[x] = make_pair( i , j ); auto check =[a]( int x ){ if( x < 0 ) return true; auto b = vector<pair<int,int>>( a.begin() , a.begin() + x ); sort( b.begin() , b.end() ); for( int i = 1 ; i < b.size() ; i ++ ) if( b[i].second < b[i-1].second ) return false; return true; }; int l = 0 , r = n*m , mid ,res = 0; while( l <= r ){ mid = ( l + r ) >> 1; if( check( mid ) ) res = mid , l = mid + 1; else r = mid - 1; } cout << res << "\n"; return; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int t; cin >> t; for (; t; t--) { solve(); } return 0; }

7|0K - 独立钻石


直接 dfs,暴力的枚举棋子和方向即可,O(6!×4)

#include <bits/stdc++.h> using namespace std; int res, n, m; const int dx[] = {0, 0, 1, -1}; const int dy[] = {1, -1, 0, 0}; void dfs(int k, vector<vector<int>> g) { res = min(res, k); if( k == 1 ) return ; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (g[i][j] == 0) continue; for (int l = 0, ax, ay, bx, by; l < 4; l++) { ax = i + dx[l], ay = j + dy[l]; if (ax < 0 || ay < 0 || ax >= n || ay >= m || g[ax][ay] == 0) continue; bx = ax + dx[l], by = ay + dy[l]; if (bx < 0 || by < 0 || bx >= n || by >= m || g[bx][by] == 1) continue; g[i][j] = 0, g[ax][ay] = 0, g[bx][by] = 1; dfs(k-1, g); g[i][j] = 1, g[ax][ay] = 1, g[bx][by] = 0; } } } } void solve() { int k; cin >> n >> m >> k; vector<vector<int>> g(n, vector<int>(m, 0)); res = k; for (int x, y; k; k--) cin >> x >> y , x -- , y -- , g[x][y] = 1; dfs(res, g); cout << res << "\n"; return; } int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int t; cin >> t; for (; t; t--) { solve(); } return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/17445779.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(396)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示