文章目录
- A - Chinchirorin
- B - AtCoder Condominium
- C - Friends and Travel costs
- D - Pond
- E - White Pawn
- F - Weed
ABC203
A - Chinchirorin
三个条件if
判
#include <cstdio>
int main() {int a, b, c;scanf( "%d %d %d", &a, &b, &c );if( a == b ) return ! printf( "%d\n", c );if( a == c ) return ! printf( "%d\n", b );if( b == c ) return ! printf( "%d\n", a );printf( "0\n" );return 0;
}
B - AtCoder Condominium
for
循环
#include <cstdio>
int main() {int n, k;scanf( "%d %d", &n, &k );int ans = 0;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= k;j ++ )ans += i * 100 + j;printf( "%d\n", ans );return 0;
}
C - Friends and Travel costs
sort
后再for
扫一遍
#include <cstdio>
#include <algorithm>
using namespace std;
#define int long long
#define maxn 200005
struct node {int pos, w;
}p[maxn];
int n, k;bool cmp( node x, node y ) {return x.pos < y.pos;
}signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ )scanf( "%lld %lld", &p[i].pos, &p[i].w );sort( p + 1, p + n + 1, cmp );int ans = k, pos = 0;for( int i = 1;i <= n;i ++ )if( pos + ans >= p[i].pos ) {ans -= ( p[i].pos - pos );ans += p[i].w;pos = p[i].pos;}else break;printf( "%lld\n", pos + ans );return 0;
}
D - Pond
非常朴素的扣出每一个正方形暴力做,O(nmk2)O(nmk^2)O(nmk2)
就是把每个数当成可能成为的答案做
既然每个数都来一次超时,那就二分
二分中位数,用二维前缀和做
设fi,j:f_{i,j}:fi,j: k×kk\times kk×k正方形的右下角为(i,j)(i,j)(i,j),该正方形中严格大于中位数的个数
设sumi,j:sum_{i,j}:sumi,j: 第jjj列的1→i1\rightarrow i1→i中严格大于中位数的个数
中位数在第⌊k22⌋+1\lfloor\frac{k^2}{2}\rfloor+1⌊2k2⌋+1位,那么严格大于的个数就为⌊k22⌋\lfloor\frac{k^2}{2}\rfloor⌊2k2⌋
只需要判断有没有某个正方形中fi,jf_{i,j}fi,j比要求个数小的,这说明该正方形的中位数应该更小,那么二分值往下调;否则往上调
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define maxn 805
int n, k, t, ans = 1e18;
int a[maxn][maxn], sum[maxn][maxn], f[maxn][maxn];int c( int x ) {if( x < 0 ) return 0;else return x;
}bool check( int x ) {for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )sum[i][j] = ( a[i][j] > x ), f[i][j] = 0;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )sum[j][i] += sum[j - 1][i];for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ ) {f[i][j] = f[i][j - 1] - ( sum[i][c(j - k)] - sum[c(i - k)][c(j - k)] ) + ( sum[i][j] - sum[c(i - k)][j] );if( i >= k && j >= k && f[i][j] <= t ) return 1;}return 0;
}signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%lld", &a[i][j] );t = k * k / 2;int l = 0, r = 1e9;while( l <= r ) {int mid = ( l + r ) >> 1;if( check( mid ) ) ans = mid, r = mid - 1;else l = mid + 1;}printf( "%lld\n", ans );return 0;
}
E - White Pawn
如果i+1i+1i+1行一个黑格子都没有,那么i+1i+1i+1行的状态与iii是一样的,nnn的级别一下子被压成了mmm级别
每一层最多往外扩222,那么整体来说到达点数硬存下来也是可行的
设Si={whitecanreach(x,y)indepthi}S_i=\bigg\{white\ can\ reach\ (x,y)\ in\ depth_i\bigg\}Si={white can reach (x,y) in depthi}
-
(j−1∈Si−1⋃j+1∈Si−1)⋂j∉Si−1⇒j∈Si(j-1∈S_{i-1}\bigcup j+1∈S_{i-1})\bigcap j∉ S_{i-1}\Rightarrow j∈S_i(j−1∈Si−1⋃j+1∈Si−1)⋂j∈/Si−1⇒j∈Si
因为写法其实SSS是一个,如果jjj之前已经在里面了,就没必要加了(虽然用的是自动去重
set
) -
j−1∉Si−1⋂j+1∉Si−1⋂j∈Si−1⇒j∉Sij-1∉S_{i-1}\bigcap j+1∉S_{i-1}\bigcap j∈ S_{i-1}\Rightarrow j∉S_ij−1∈/Si−1⋂j+1∈/Si−1⋂j∈Si−1⇒j∈/Si
#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
set < int > s;
vector < int > Old, New;
vector < pair < int, int > > g;
int n, m;int main() {scanf( "%d %d", &n, &m );for( int i = 0, x, y;i < m;i ++ ) {scanf( "%d %d", &x, &y );g.push_back( make_pair( x, y ) );}sort( g.begin(), g.end() );s.insert( n );for( int l = 0, r;l < m;l = r ) {for( r = l;r < m && g[l].first == g[r].first;r ++ );New.clear(), Old.clear();for( int i = l;i < r;i ++ ) {int k = g[i].second;if( ( s.find( k - 1 ) != s.end() || s.find( k + 1 ) != s.end() ) && ( s.find( k ) == s.end() ) ) New.push_back( k );if( ( s.find( k - 1 ) == s.end() && s.find( k + 1 ) == s.end() ) && ( s.find( k ) != s.end() ) ) Old.push_back( k );}for( int i = 0;i < New.size();i ++ ) s.insert( New[i] );for( int i = 0;i < Old.size();i ++ ) s.erase( Old[i] );}printf( "%d\n", s.size() );return 0;
}
F - Weed
由于特殊操作⌊H2⌋\lfloor\frac{H}{2}\rfloor⌊2H⌋在,不难发现,操作次数是logN\log NlogN级别的
将杂草高度排序,直接枚举操作次数,记fi,j:f_{i,j}:fi,j: 第iii次操作到jjj杂草为止拔草的最大数目
fi−1,k+∑ak>⌊aj2⌋,k≤j1→fi,jf_{i-1,k}+\sum_{a_k>\lfloor\frac{a_j}{2}\rfloor,k\le j}1\rightarrow f_{i,j}fi−1,k+∑ak>⌊2aj⌋,k≤j1→fi,j
最后滚动掉iii这一维即可
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 200005
int f[2][maxn];
int a[maxn];
int n, k;int main() {scanf( "%d %d", &n, &k );for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );if( n == k ) return ! printf( "0 %d\n", n );sort( a + 1, a + n + 1 );int ans = 0;for( int i = 1;i <= 31;i ++ ) {int ip = 0, maxx = 0;for( int j = 1;j <= n;j ++ ) {while( ip < n && a[ip + 1] <= a[j] / 2 )maxx = max( maxx, f[i & 1 ^ 1][++ ip] );f[i & 1][j] = maxx + j - ip;ans = max( ans, f[i & 1][j] );}if( ans >= n - k ) return ! printf( "%d %d\n", i, n - ans );}return 0;
}