AtCoder Beginner Contest 203(Sponsored by Panasonic)题解


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 ( n m k 2 ) O(nmk^2) O(nmk2)

就是把每个数当成可能成为的答案做

既然每个数都来一次超时,那就二分

二分中位数,用二维前缀和做

f i , j : f_{i,j}: fi,j: k × k k\times k k×k正方形的右下角为 ( i , j ) (i,j) (i,j),该正方形中严格大于中位数的个数

s u m i , j : sum_{i,j}: sumi,j: j j j列的 1 → i 1\rightarrow i 1i严格大于中位数的个数

中位数在第 ⌊ k 2 2 ⌋ + 1 \lfloor\frac{k^2}{2}\rfloor+1 2k2+1位,那么严格大于的个数就为 ⌊ k 2 2 ⌋ \lfloor\frac{k^2}{2}\rfloor 2k2

只需要判断有没有某个正方形中 f i , j f_{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 + 1 i+1 i+1行一个黑格子都没有,那么 i + 1 i+1 i+1行的状态与 i i i是一样的, n n n的级别一下子被压成了 m m m级别

每一层最多往外扩 2 2 2,那么整体来说到达点数硬存下来也是可行的

S i = { w h i t e   c a n   r e a c h   ( x , y )   i n   d e p t h i } S_i=\bigg\{white\ can\ reach\ (x,y)\ in\ depth_i\bigg\} Si={white can reach (x,y) in depthi}

  • ( j − 1 ∈ S i − 1 ⋃ j + 1 ∈ S i − 1 ) ⋂ j ∉ S i − 1 ⇒ j ∈ S i (j-1∈S_{i-1}\bigcup j+1∈S_{i-1})\bigcap j∉ S_{i-1}\Rightarrow j∈S_i (j1Si1j+1Si1)j/Si1jSi

    因为写法其实 S S S是一个,如果 j j j之前已经在里面了,就没必要加了(虽然用的是自动去重set)

  • j − 1 ∉ S i − 1 ⋂ j + 1 ∉ S i − 1 ⋂ j ∈ S i − 1 ⇒ j ∉ S i j-1∉S_{i-1}\bigcap j+1∉S_{i-1}\bigcap j∈ S_{i-1}\Rightarrow j∉S_i j1/Si1j+1/Si1jSi1j/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

由于特殊操作 ⌊ H 2 ⌋ \lfloor\frac{H}{2}\rfloor 2H在,不难发现,操作次数是 log ⁡ N \log N logN级别的

将杂草高度排序,直接枚举操作次数,记 f i , j : f_{i,j}: fi,j: i i i次操作到 j j j杂草为止拔草的最大数目

f i − 1 , k + ∑ a k > ⌊ a j 2 ⌋ , k ≤ j 1 → f i , j f_{i-1,k}+\sum_{a_k>\lfloor\frac{a_j}{2}\rfloor,k\le j}1\rightarrow f_{i,j} fi1,k+ak>2aj,kj1fi,j

最后滚动掉 i i i这一维即可

#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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值