20220701 SMU&CUIT友谊赛(题目来源2021ccpc女生赛)

反思其实这套题签到题还是比较多大,而且能做的难题恰好也是我比较擅长的dfs。但是本次比赛中犯的最大的错误就是没有及时看榜,但是别人已经写了三道签到题了我还没有过题

1|0A


这道题的做法比较简单就是正反各跑一遍判断,然后根据判断结果判断答案

#include<bits/stdc++.h> using namespace std; const int N = 30; int n , x , y , m ; int k[N] , p[N]; int32_t main() { cin >> n >> x >> y; for( int i = 1 ; i <= n ; i ++ ) cin >> k[i]; cin >> m; for( int i = 1 ; i <= m ; i ++ ) cin >> p[i]; int f1 = 1 , f2 = 1; if( x + m > n ) f1 = 0; if( x - m < 1 ) f2 = 0; for( int i = x + 1 ; i <= x + m && f1 ; i ++ ) if( p[i-x] != k[i] ) f1 = 0; for( int i = x - 1 ; i >= x - m && f2 ; i -- ) if( p[x-i] != k[i] ) f2 = 0; if( f1 && f2 ) cout << "Unsure\n"; else if( f1 && y > x ) cout << "Right\n"; else if( f2 && y < x ) cout << "Right\n"; else cout << "Wrong\n"; return 0; }

2|0C


正解是状压dp。我通过 dfs+剪枝过掉了这题,并且跑的还算比较快

首先在一条路径上,如果某个公司的商店前后出现了多次,那么在第一次出现的时候领取优惠券是最优的选择。证明可以参考反证法。

在路径 1 -> 2 -> 3 上,1 和 3 属于同一家公司。如果不在 1 选择,就要在 3 选择,对于 3 点来说结果没有影响,但是对于 1 来说,因为不选导致不是最优解

其次第二个性质就是如果有两条路径分别是1->2->3->41->4,对于1,2,3来说只有一条路径,但是对于4来说有两条路径,然后可以发现选择1->2->3->4不会比1->4结果更差,所以1->4这条路径删掉对答案是没哟影响的,依次类推可以把图中这样变都删掉,这样整个图一下子就变成了稀疏图。这个结论是剪枝的关键。

然后根据上述的性质,先把图中的边都删掉,然后dfs 遍历图,加上一点点最优性剪枝就可以把这题过掉了

#include<bits/stdc++.h> using namespace std; 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 N = 40; int n , m , c[N] , w[N] , ans[N]; int g[N][N]; long long cnt[N]; int vis[N]; vector< int > e[N]; void dfs( int x , int sum , long long t ){ // t 是一个状压剪枝 vis[ c[x] ] ++ ; if( vis[ c[x] ] == 1 ) sum += w[ c[x] ] , t ^= (1<<c[x] ); if( ans[x] == sum && t == cnt[x] ) { vis[c[x]] --; return; } else if ( sum > ans[x] ) ans[x] = sum , cnt[x] = t; ans[x] = max( sum , ans[x] ); for( auto it : e[x] ) dfs( it , sum , t ); vis[ c[x] ] -- ; } int32_t main() { n = read() , m = read(); for( int i = 1 ; i <= n ; i ++ ) c[i] = read(); for( int i = 1 ; i <= n ; i ++ ) w[i] = read(); for( int u , v ; m ; m -- ) u = read() , v = read() , g[u][v] = 1 ; for( int k = 1 ; k <= n ; k ++ ) for( int i = 1 ; i < k ; i ++ ) for( int j = k + 1 ; j <= n ; j ++ ) if( g[i][j] && g[i][k] && g[k][j] ) g[i][j] = 0; // 删边 for( int i = 1 ; i <= n ; i ++ ) // 重新建图 for( int j = i + 1 ; j <= n ; j ++ ) if( g[i][j] ) e[i].push_back(j); dfs( 1 , 0 , 0 ); for( int i = 1 ; i <= n ; i ++ ) printf("%d\n" , ans[i] ); return 0; }

3|0D


这题很有意思的,假设我们已经链接了n-2条边 就差最后一条边了,现在的情况是1...k 连在一起k+1…n连在一起。所以最后一条边就是从 1...k中选择一个点l,然后从k+1...n中选择一个点r,然后边权就是l..。r中的最大值。然后我们发现lk1移动的过程中l...r的最大值只会越来越大,同理rk+1n移动的过程也是这的,所以令l=k,r=k+1才是最优解,边权就是max( a[l] , a[r])

然后我们不断的递归链接确定边权就会发现答案就是

i=2nmax(ai1,ai)

#include<bits/stdc++.h> #define int long long using namespace std; const int N = 2e5+5; int a[N] , n , ans; int read() { int x = 0, f = 1, ch = getchar(); while ((ch < '0' || ch > '9') && ch != '-') ch = getchar(); if (ch == '-') f = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x * f; } int32_t main() { n = read(); for( int i = 1 ; i <= n ; i ++ ) a[i] = read(); for( int i = 2 ; i <= n ; i ++ ) ans += max( a[i] , a[i-1] ); cout << ans << endl; return 0; }

4|0G


这道题是小思路,当半径无穷大的时候,每一个圆都可以覆盖整个小镇,所以答案就是1n

#include<bits/stdc++.h> using namespace std; int main(){ double a; cin >> a; printf("%.15llf\n" , 1/a ); }

5|0I


按照题目模拟好了

#include<bits/stdc++.h> //#define int long long #define fx ( x + dx[d] ) #define fy ( y + dy[d] ) using namespace std; const int N = 55; const int dx[] = { -1 , -1 , 0 , 1 , 1 , 1 , 0 , -1}; const int dy[] = { 0 , 1 , 1 , 1 , 0 , -1 , -1 , -1 }; int n , m , ans; bool mp[N][N]; int32_t main() { int x , y , v = 0 , d = 0; string s; cin >> n >> m; for( int i = 1 ; i <= n ; i ++ ) { cin >> s; for( int j = 1 ; j <= n ; j ++ ) { if( s[j-1] == '#' ) mp[i][j] = 1; if( s[j-1] == '*' ) x = i , y = j; } } int q; cin >> q >> s; for( auto it : s ){ if( it == 'R' ) d = ( d + 1 ) % 8; if( it == 'L' ) d = ( d + 7 ) % 8; if( it == 'U' ) v ++; if( it == 'D' ) v = max( 0 , v - 1 ); bool flag = 0; for( int i = 1 ; i <= v ; i ++ ){ if( fx < 1 || fy < 1 || fx > n || fy > m ){ flag = 1; v = 0; break; } if( d & 1 ){ if( ( mp[x][fy] && mp[fx][y] ) ){ flag = 1; v = 0; break; } } if( mp[fx][fy] ){ flag = 1; v = 0; break; } x = fx , y = fy; } cout << ( flag ? "Crash! " : "" ) << x << " " << y << "\n"; } return 0; }

6|0K


这题其实就是数一下-的数量就好

#include<bits/stdc++.h> using namespace std; int32_t main() { int n , cnt = 0; string s; cin >> n; getchar(); for( ; n ; n -- ) { getline( cin , s ); for( int i = 1 ; i <= 4 ; i ++) if( s[i] == '-') cnt ++; } cout << cnt << endl; return 0; }

__EOF__

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