luogu题目选做(二)

1|0P7885


从A点向B点行走的最有情况肯定是向着两个方向走,而不是四个方向。

因为,不能向一个方向连续走两次,所以最优情况是x和y交替走,必然可以走到只剩x或只剩y的情况,此时的最优解就是走长城的情况,然后假设我们需要走n步,可以再纸上模拟若n是奇数则走2×n1步若为偶数则走2×n

#include <bits/stdc++.h> #define LL long long using namespace std; int t; long long a , b , c , d , x , y , ans , cnt ; int main() { cin >> t; while( t -- ) { cin >> a >> b >> c >> d ; x = abs( a - c ) , y = abs( b - d ); ans = x + y , cnt = abs( x - y ); if( cnt > 1 ) ans += cnt - cnt % 2; cout << ans << endl; } return 0; }

2|0P7886


首先判断时候可以成立,若n×mk的倍数则一定可以,反之不行。

然后考虑构造答案。我想到的方法是走S形,因为要从后向前填颜色,可以离线涂色,最后一起输出

#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5; int n , m , k , t , color , cnt , a[N]; int main() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); cin >> t; while( t -- ) { cin >> n >> m >> k; if( n * m % k ) cout << "NO\n"; else { cout << "YES\n"; color = 1 , cnt = 0; for( int i = 1 ; i <= n ; i ++ ) { if( i % 2 ) { for( int j = 1 ; j <= m ; j ++ ) { cout << color << " "; cnt ++; if( cnt == k ) color ++ , cnt = 0; } cout << '\n'; } else { for( int j = m ; j >= 1 ; j -- ) { a[j] = color; cnt ++; if( cnt == k ) color ++ , cnt = 0; } for( int j = 1; j <= m ; j ++ ) cout << a[j] << ' '; cout << '\n'; } } } } }

3|0P7893


举一个例子15 3答案是11,然后我们将1到15进行分组

1 3 9 2 6 4 12 5 15 7 8 9 10 11 13 14

很显然对于每一行来说我们的最有解就是隔一个选一个

对于第1列我们发现这些数都不是31的倍数,同理第二列都不是32的倍数,即第i列都不是pi的倍数

对于第一列是数的总数是( n / p ) * ( p - 1 ) + ( x % p ) ,然后我们n /= p * p 再算一遍就是

第三列,所以循环操作直到n==0结束循环

#include <bits/stdc++.h> #define f( x ) ( ( x / p ) * ( p - 1 ) + ( x % p ) ) using namespace std; long long t , n , ans , p ; inline long long read() { register long long x = 0; register char 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; } int main() { t = read(); while( t -- ) { n = read() , p = read() , ans = 0; if( p == 1 ) { puts("0"); continue; } for( ; n ; n /= p * p ) ans += f(n); printf( "%lld\n" , ans ); } return 0; }

4|0P7892


数据范围太小直接枚举边长,计算栅栏长度

#include <bits/stdc++.h> using namespace std; int t , n , m , f ; inline int read() { register int x = 0; register char 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; } int main() { t = read(); while( t -- ) { n = read() , m = read() , f = 0 ; for( register int i = 1 ; i * i <= n && !f ; i ++ ) { if( n % i ) continue; if( ( i + n/i + 2 ) * 2 <= m ) f = 1 , puts("Good"); } if( !f ) puts("Miss"); } return 0; }

5|0P1197


离线做,倒着枚举被攻击点,将删点变成加点,加点的同时加所有与该点相连且另一点也存在的边,如果加边前两个点不在同一个连通块中,连通块总数减一

#include <bits/stdc++.h> using namespace std; const int N = 1000005; int n , k , m , fa[N] , attack[N] , ans[N] ; bool vis[N]; vector < int > e[N]; inline int read() { register int x = 0; register char 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; } inline void addedge( const int &x , const int &y ) { e[x].push_back( y ) , e[y].push_back( x ); return; } inline int getfa( int x ) { return fa[x] = ( ( fa[x] == x ) ? x : getfa( fa[x] ) ); } inline void merage( int x , int y ) { register int fx = getfa( x ) , fy = getfa( y ) ; fa[ fx ] = fy ; return; } int main() { n = read() , m = read(); for( register int i = 1 ; i <= n ; i ++ ) fa[i] = i; for( register int i = 1 , x , y ; i <= m ; i ++ ) x = read()+ 1 , y = read() + 1 , addedge( x , y ); k = read(); for( register int i = 1 ; i <= k ; i ++ ) attack[i] = read() + 1 , vis[ attack[i] ] = 1; for( register int i = 1 ; i <= n ; i ++ ) { if( vis[i] ) continue; for( auto it : e[i] ) { if( vis[ it ] ) continue; merage( it , i ); } } for( register int i = 1 ; i <= n ; i ++ ) if( !vis[i] && fa[i] == i ) ans[k] ++; for( register int i = k , fx , fy ; i >= 1 ; i -- ) { ans[ i - 1 ] = ans[i] + 1 , vis[ attack[i] ] = 0 , fx = getfa( attack[i] ); for( auto it : e[ attack[i] ] ) { if( vis[it] ) continue; fy = getfa( it ); if( fx == fy ) continue; fa[fy] = fx , ans[ i - 1 ] --; } } for( register int i = 0 ; i <= k ; i ++ ) printf( "%d\n" , ans[i] ); return 0; }

6|0P3397


6|1差分


将每一行单独来做差分,最后对每一行求前缀和并输出

#include<bits/stdc++.h> using namespace std; const int N = 1005; int n , m , a[N][N]; inline int read() { register int x = 0; register char 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; } int main() { n = read() , m = read(); for( register int i = 1 , x_1 , x_2 , y_1 , y_2 ; i <= m ; i ++ ) { x_1 = read() , y_1 = read() , x_2 = read() , y_2 = read(); for( register int j = x_1 ; j <= x_2 ; j ++ ) a[j][ y_1 ] ++ , a[j][ y_2 + 1 ] --; } for( register int i = 1 ; i <= n ; i ++ ) { for( register int j = 1 ; j <= n ; j ++ ) printf( "%d " , a[i][j] += a[i][ j - 1 ] ); printf("\n"); } return 0; }

6|2二维差分


求二维差分的方法是

b[i][j] = a[i][j] - a[ i - 1 ][j] - a[i][ j - 1 ] + a[ i - 1 ][ j - 1 ]

( x1 , y1 ) ( x2 , y2 )进行区间修改的方法为

b[x1][y1] ++ , b[x1][ y2 + 1 ] -- , b[ x2 + 1 ][y1] -- , b[ x2 + 1 ][ y2 + 1 ] ++

还原的方法为

a[i][j] = b[i][j] + b[ i - 1 ][j] + b[i][ j - 1 ] - b[ i - 1 ][ j - 1 ]

#include<bits/stdc++.h> using namespace std; const int N = 1005; int n , m , a[N][N]; inline int read() { register int x = 0; register char 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; } int main() { n = read() , m = read(); for( register int i = 1 , x_1 , x_2 , y_1 , y_2 ; i <= m ; i ++ ) { x_1 = read() , y_1 = read() , x_2 = read() , y_2 = read(); a[x_1][y_1] ++ , a[ x_2 + 1 ][ y_1 ] -- , a[ x_1 ][ y_2 + 1 ] -- , a[ x_2 + 1 ][ y_2 + 1 ] ++; } for( register int i = 1 ; i <= n ; i ++ ) { for( register int j = 1 ; j <= n ; j ++ ) printf( "%d " , a[i][j] += a[ i - 1 ] [j] + a[i][ j - 1 ] - a[ i - 1 ][ j - 1 ] ); puts(""); } return 0; }

数据水,两种做法差别不大

7|0CF18C


做一遍前缀和,枚举第一组数的右端点

#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; int n , a[N] , cnt = 0; inline int read() { register int x = 0 , f = 1; register char 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; } int main() { n = read(); for( register int i = 1 ; i <= n ; i ++ ) a[i] = a[ i - 1 ] + read(); for( register int i = 1 ; i < n ; i ++ ) if( a[i] << 1 == a[n] ) cnt ++; cout << cnt << endl; return 0; }

8|0CF17B


用类似Kruskal的方法,把边进行排序,然后枚举每条边,判断v是否已经有上司,如果没有就加边

#include <bits/stdc++.h> using namespace std; const int N = 1e3 +5 , M = 1e4 +5; int n , m , val[N] , cnt = 0 , father[N] , tt = 0; long long ans; struct edge { int u , v , w ; friend bool operator < ( edge a , edge b ) { return a.w < b.w;} } e[M]; inline int read() { register int x = 0; register char 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 ; } int main() { n = read(); for( register int i = 1 ; i <= n ; i ++ ) val[i] = read(); m = read(); for( register int i = 1 , u , v , w ; i <= m ; i ++ ) { u = read() , v = read() , w = read(); if( val[u] < val[v] ) continue; cnt ++ , e[cnt].u = u , e[cnt].v = v , e[cnt].w = w; } sort( e + 1 , e + 1 + cnt); for( register int i = 1 ; i <= cnt ; i ++ ) { if( father[ e[i].v ] ) continue; father[ e[i].v ] = 1, ans += e[i].w , tt ++ ; if( tt == n - 1 ) continue; } if( tt == n - 1 ) cout << ans << endl; else puts("-1"); return 0; }

9|0AT795


贪心做,首先要选择最大的k个数,其实越早选择除2的次数越多,所以越大的数越后选择

#include <bits/stdc++.h> using namespace std; int n , k; double ans; vector< int > a; inline int read() { register int x = 0; register char ch = getchar(); while( ch < '0' || ch > '9' ) ch = getchar(); while( ch >= '0' && ch <= '9' ) x = x * 10 + ch - '0' , ch = getchar(); return x; } int main() { n = read() , k = read(); for( register int i = 1 ; i <= n ; i ++ ) a.push_back( read() ); sort( a.begin() , a.end() ); for( register int i = n - k ; i < n ;i ++ ) ans = ( ans + a[i] ) / 2.0; printf( "%.6lf\n" , ans ); return 0; }

10|0P1249


暴力的枚举枚举每一个起点,然后用DFS遍历从该点开始的最长子链。

#include<bits/stdc++.h> #define to first #define val second using namespace std; const int N = 25; int n , m , max_len = -1; bool v[N]; vector< pair< int , int > > e[N]; void dfs( int x , int sum ) { if( v[x] ) return ; // cout << x << ' ' << sum << endl; max_len = max( max_len , sum ) , v[x] = 1; for( auto it : e[x] ) dfs( it.to , it.val + sum ); v[x] = 0; } int main() { cin >> n >> m; for( int i = 1 , x , y , z ; i <= m ; i ++ ) { cin >> x >> y >> z; e[x].push_back( { y , z } ) , e[y].push_back( { x , z } ); } for( int i = 1 ; i <= n ; i ++ ) { dfs( i , 0 ); memset( v , 0 , sizeof( v ) ); } cout << max_len << endl; return 0; }

11|0P7001


数据范围小,O(n)暴力匹配即可,遇到星号跳过即可。

#include <bits/stdc++.h> using namespace std; const int N = 1005; int n , cnt = 0; string s , x , ans[N]; int main() { cin >> s >> n ; for( register int i = 1 , f ; i <= n ; i ++ ) { cin >> x; f = 1; for( register int j = 0 ; j < s.size() && f ; j ++ ) { if( s[j] == '*' ) continue; if( s[j] != x[j] ) f = 0; } if( f ) cnt ++ , ans[cnt] = x; } cout << cnt << endl; for( register int i = 1 ; i <= cnt ; i ++ ) cout << ans[i] << endl; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/15412668.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(53)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示