SMU Spring 2023 Trial Contest Round 2

A - 生活大爆炸版石头剪刀布

B - 联合权值

C - 飞扬的小鸟

D - 无线网络发射器选址

E - 寻找道路

F - 廊桥分配

G - 格雷码

1|0A - 生活大爆炸版石头剪刀布


这套题就是注意处理一下输赢关系就好了

#include <bits/stdc++.h> using namespace std; int check( int x , int y ){ if( x == y ) return 0; if( x == 0 ){ if( y == 1 || y == 4 ) return -1; return 1; }else if( x == 1 ){ if( y == 2 || y == 4 ) return -1; return 1; }else if( x == 2 ){ if( y == 0 || y == 3 ) return -1; return 1; }else if( x == 3 ){ if( y == 1 || y == 0 ) return -1; return 1; }else{ if( y == 2 || y == 3 ) return -1; return 1; } } int main(){ int n , na , nb; cin >> n >> na >> nb; vector<int> a(na) , b(nb); for( auto &i : a ) cin >> i; for( auto &i : b ) cin >> i; int cnta = 0 , cntb = 0; for( int i = 0 , t ; i < n ; i ++ ){ t = check( a[ i%na ] , b[ i%nb ] ); if( t == 1 ) cnta ++; if( t == -1 ) cntb ++; } cout << cnta << " " << cntb << "\n"; return 0; }

2|0B - 联合权值


任意点相邻点之前的最短距离一定是2,这是因为是一个图。

一个点相邻的点的权值是wi,所以最大值就是最大和次大值相乘。令W=wi,则联合权值和就是wi(Wwi)

#include <bits/stdc++.h> using namespace std; #define int long long int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } const int mod = 10007; int32_t main(){ int n = read() , res = 0 , sum = 0; vector<vector<int>> e(n+1); vector<int> w(n+1); for( int u , v , i = n-1 ; i ; i -- ) u = read() , v = read() , e[u].push_back(v) , e[v].push_back(u); for( int i = 1 ; i <= n ; i ++ ) w[i] = read(); for( int i = 1 , a , b , cnt; i <= n ; i ++ ){ a = 0 , b = 0 , cnt = 0; for( auto j : e[i] ){ cnt = (cnt + w[j]) % mod; if( w[j] >= a ) b = a , a = w[j]; else b = max(b , w[j]); } res = max( res , a * b ); for( auto j : e[i] ){ cnt = ( cnt - w[j] + mod ) % mod; sum = ( sum + cnt * w[j] ) % mod; } } cout << res << " " << sum * 2 % mod << "\n"; return 0; }

3|0C - 飞扬的小鸟(补题)


dp题目,注意点就是在每个位置其实可以无限次向上飞的,但是高度最高只能到m

f[i][j]表示飞到i高度j的最少向上飞的次数,用正无穷表示无法到达

#include <bits/stdc++.h> using namespace std; #define int long long int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ int n = read() , m = read() , k = read(); vector<int> up(n+1) , down(n+1); for( int i = 1 ; i <= n ; i ++ ) up[i] = read() , down[i] = read(); vector<int> lower(n+1, 1 ) , upper(n+1, m) , pipeline; for( int a , b , c ; k ; k -- ) a = read(), b = read(), c = read(), lower[a] = b + 1, upper[a] = c - 1, pipeline.push_back(a); vector<vector<int>> f( n+1 , vector<int>( m+1 , INT_MAX ) ); for( int i = 1 ; i <= m ; i ++ ) f[0][i] = 0; for( int i = 1 ; i <= n ; i ++ ){ for( int j = up[i]+1 ; j <= m ; j ++ ) f[i][j] = min( f[i-1][j-up[i]] + 1 , f[i][j-up[i]] + 1 ); for( int j = m+1 ; j <= m+up[i] ; j ++ ) f[i][m] = min( {f[i][m] , f[i-1][j-up[i]] + 1, f[i][j-up[i]] + 1 } ); for( int j = 1 ; j <= m-down[i] ; j ++ ) f[i][j] = min( f[i][j] , f[i-1][j+down[i]] ); for( int j = 1 ; j < lower[i] ; j ++ ) f[i][j] = INT_MAX; for( int j = upper[i]+1 ; j <= m ; j ++ ) f[i][j] = INT_MAX; } int res = INT_MAX; for( int i = 1 ; i <= m ; i ++ ) res = min( res , f[n][i] ); if( res < INT_MAX ) return cout << "1\n" << res <<"\n" , 0; sort(pipeline.begin(), pipeline.end()); int cnt = 0; for( auto i : pipeline ){ int flag = 0; for( int j = 1 ; j <= m ; j ++ ) if( f[i][j] < INT_MAX ){ flag = 1; break; } cnt += flag; } cout << "0\n" << cnt << "\n"; return 0; }

4|0D - 无线网络发射器选址


二维前缀和,直接枚举中心点的位置就好了

#include <bits/stdc++.h> using namespace std; #define int long long const int N = 150; int f[N][N]; int d , n , res = -1 , cnt = 0; int32_t main(){ cin >> d >> n; for( int x , y , k ; n ; n -- ){ cin >> x >> y >> k; x ++ , y ++; f[x][y] += k; } for( int i = 1 ; i <= 129 ; i ++ ) for( int j = 1 ; j <= 129 ; j ++ ) f[i][j] = f[i][j] + f[i-1][j] + f[i][j-1] - f[i-1][j-1]; for( int i = 1 , t ; i <= 129 ; i ++ ) for( int j = 1 , x , y , a , b ; j <= 129 ; j ++ ){ x = max( 1ll , i-d ) , y = max( 1ll , j-d ); a = min( 129ll , i+d ) , b = min( 129ll , j+d ); t = f[a][b] - f[a][y-1] - f[x-1][b] + f[x-1][y-1]; if( t > res ) res = t , cnt = 1; else if( t == res ) cnt ++; } cout << cnt << " " << res; return 0; }

5|0E - 寻找道路


首先反向建图,然后从终点开始找出所有可以到达终点的点。然后再预处理出所有满足条件 1 的点。最后跑 Dijkstra 就行。

#include <bits/stdc++.h> using namespace std; #define int long long const int N = 150; int f[N][N]; int d , n , res = -1 , cnt = 0; int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ int n = read() , m = read(); vector< vector<int> > e(n+1) , g(n+1); for( int u , v ; m ; m -- ) u = read() , v = read() , e[u].push_back(v) , g[v].push_back(u); int s = read() , t = read(); vector<bool> tag(n+1 , false); queue<int> q; q.push(t); while( !q.empty() ){ int u = q.front(); q.pop(); if( tag[u] ) continue; tag[u] = true; for( auto v : g[u] ){ if( tag[v] ) continue; q.push(v); } } vector<bool> can(n+1 , true ); for( int i = 1 ; i <= n ; i ++ ) for( auto v : e[i] ) if( tag[v] == false ) { can[i] = false; break; } vector<bool> vis(n+1 , false); vector<int> dis(n+1 , INT_MAX ); priority_queue< pair<int,int> , vector<pair<int,int>> , greater<pair<int,int>> > heap; dis[s] = 0 , heap.emplace(0 , s); while( !heap.empty() ){ auto [ d , u ] = heap.top(); heap.pop(); if( vis[u] ) continue; vis[u] = true; if( can[u] == false ) continue; for( auto v : e[u] ){ if( vis[v] || can[v] == false ) continue; if( dis[v] <= d + 1 ) continue; dis[v] = d + 1 , heap.emplace( dis[v] , v ); } } if( dis[t] == INT_MAX ) dis[t] = -1; cout << dis[t]; return 0; }

6|0F - 廊桥分配(补题)


6|145%做法


枚举廊桥的分配方案,然后用堆来计算可以停靠的飞机总数

#include <bits/stdc++.h> using namespace std; #define int long long const int N = 150; int f[N][N]; int d , n , res = -1 , cnt = 0; int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ freopen("airport.in","r",stdin); freopen("airport.out","w",stdout); int n = read() , m1 = read() , m2 = read(); vector<pair<int,int>> a(m1) , b(m2); for( auto &[l,r] : a ) l = read() , r = read(); for( auto &[l,r] : b ) l = read() , r = read(); sort(a.begin(), a.end()) ,sort(b.begin(), b.end()); int res = 0; priority_queue<int,vector<int> , greater<int>> q; for( int i = 0 , j , cnt ; i <= n ; i ++ ){ j = n-i , cnt = 0; q = priority_queue<int,vector<int> , greater<int>>(); for(auto [l,r] : a ){ while( !q.empty() && q.top() <= l ) q.pop(); if( q.size() + 1 <= i ) q.push(r) , cnt ++; } q = priority_queue<int,vector<int> , greater<int>>(); for( auto [l,r] : b ){ while( !q.empty() && q.top() <= l ) q.pop(); if( q.size() + 1 <= j ) q.push(r) , cnt ++; } res = max( res , cnt ); } cout << res << "\n"; return 0; }

6|2AC


改变一下贪心策略,在同时有多个廊桥可以停靠时优先选择标号小的。然后统计出每个廊桥停靠的飞机总数,在求前缀和就得到了如果分配了i个廊桥最多可以停靠多少飞机。把国内国际都处理完后,在枚举分配情况,O(1)计算最多可以停靠的飞机总数即可

#include <bits/stdc++.h> using namespace std; #define int long long int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ freopen("airport.in","r",stdin); freopen("airport.out","w",stdout); int n = read() , m1 = read() , m2 = read(); vector<pair<int,int>> a(m1) , b(m2); for( auto &[l,r] : a ) l = read() , r = read(); for( auto &[l,r] : b ) l = read() , r = read(); sort(a.begin(), a.end()) ,sort(b.begin(), b.end()); vector<int> resA(n+1); priority_queue< pair<int,int> , vector<pair<int,int>> , greater<pair<int,int>> > lq; priority_queue< int , vector<int> , greater<int> > wq; for( auto i = 1 ; i <= n ; i ++ ) wq.push(i); for( auto [l,r] : a ){ while( !lq.empty() && lq.top().first <= l ) wq.push( lq.top().second ) , lq.pop(); if( wq.empty() ) continue; lq.emplace( r , wq.top() ) , resA[wq.top()] ++ , wq.pop(); } vector<int> resB(n+1); lq = priority_queue< pair<int,int> , vector<pair<int,int>> , greater<pair<int,int>> >(); wq = priority_queue< int , vector<int> , greater<int> >(); for( auto i = 1 ; i <= n ; i ++ ) wq.push(i); for( auto [l,r] : b ){ while( !lq.empty() && lq.top().first <= l ) wq.push( lq.top().second ) , lq.pop(); if( wq.empty() ) continue; lq.emplace( r , wq.top() ) , resB[wq.top()] ++ , wq.pop(); } for( int i = 1 ; i <= n ; i ++ ) resA[i] += resA[i-1] , resB[i] += resB[i-1]; int res = 0; for( int i = 0 , j ; i <= n ; i ++ ) j = n - i , res = max( res , resA[i] + resB[j] ); cout << res << "\n"; return 0; }

7|0G - 格雷码(补题)


7|150%做法


直接暴力出结果

#include <bits/stdc++.h> using namespace std; #define int long long const int N = 150; int f[N][N]; int d , n , res = -1 , cnt = 0; int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ freopen("code.in","r",stdin); freopen("code.out","w",stdout); int n = read() , k = read(); if( n == 1 ) { cout << k << "\n"; return 0; } vector<string> a , b; a.push_back("0") , a.push_back("1"); for( int i = 2 ; i <= n ; i ++ ){ b.clear(); for( auto s : a ) b.push_back( "0" + s ); reverse(a.begin(),a.end()); for( auto s : a ) b.push_back( "1" + s ); a = b; } cout << a[k] << "\n"; return 0; }

7|2AC


计算出第n位长度,判断是在前半部分还是后半部分,如果在前半部分就是补一个 0,否则就补一个 1。

设第n位长度数p,如果实在后半部分的话,实际上是在后半部分的kp2的,但是以为后半部分是要把序列逆序,所以下一步实际上应该是第p2(kp2)=pk个格雷码

#include <bits/stdc++.h> using namespace std; #define int __int128 typedef long long ll; int read(){ int x = 0 , ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar(); return x; } int32_t main(){ freopen("code.in","r",stdin); freopen("code.out","w",stdout); int n = read() , k = read(); string s = ""; int p = ((int)1 << n ) - 1 , mid = p >> 1; while( true ){ if( n == 1 ){ if( k == 1 ) s += "1"; else s += "0"; break; } if( k <= mid ) s += "0"; else k = p - k , s += "1"; n -- , p >>= 1 , mid >>= 1; } cout << s; return 0; }

__EOF__

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