AtCoder 第400场初级竞赛 A~E题解

 A ABC400 Party(ABC400 党)

【题目链接】

原题链接:A - ABC400 Party

【考点】

判断

【题目大意】

400人排成一个矩形队形,输入多少人一排,求要多少列。

【解析】

如果能够整除400,这输出 400 / n,否则输出 -1。

【难度】

GESP二级

【代码参考】

#include<bits/stdc++.h>
using namespace std;


int main(){
	int n;
	cin >> n;
	if(400 % n == 0)
		cout << 400 / n;
	else cout << -1;
	return 0;
}

 B Sum of Geometric Series(几何级数之和)

【题目链接】

原题链接:B - Sum of Geometric Series

【考点】

枚举

【题目大意】

求 n 的 1~m 次方的和。

【解析】

主要是计算一个特定的数列求和,并判断求和结果是否会超出给定的范围(在代码中该范围上限定义为 N = 1e9)。若超出范围或者在计算过程中出现溢出(结果为负数),则输出" inf ";否则,输出计算得到的求和结果。将 ans 乘以 n,相当于计算 n 的幂次。

【难度】

GESP二级

【代码参考】

#include<bits/stdc++.h>
using namespace std;

const int N = 1e9;

int main(){
	int n, m, f = 0;
	int ans = 1, x = 1;
	cin >> n >> m;
	for(int i = 0; i < m; i++){
		ans *= n;
		if(x + ans > N){
			f = 1;
			break;
		}
		x += ans;
	}
	if(x < 0 || f) cout << "inf";
	else cout << x;
	return 0; 
}

 C 2^a b^2

【题目链接】

原题链接:C - 2^a b^2

【考点】

二分查找

【题目大意】

存在一对正整数 (a,b) 使得 x = 2^a × b^2。

【解析】

拆分成求 2 的幂次和 b 的平方,先对 n 除 2,相当于在求 2 的 1 次方的组合(不断除以 2 就是在求各个 2 的幂次组合),再求小于商的最大平方数,那么该数的平方根就是 b 的可能个数。因为偶数是要分到其他 2 的幂次组合,这里只去奇数的个数,避免计算重复。

【难度】

GESP五级

【代码参考】

#include<bits/stdc++.h>
using namespace std;

int main(){
	long long n, a[100], m = 1;
	int ans = 0;
	cin >> n;
	for(int i = 1; i <= 60; i++){
		m = n >> i; // 除以2的 a次方 
		if(m == 0) continue;
		long long l = 1, r = 1000000000;
		while(l + 1 != r){ // 查找最大的 b 
			long long mid = (l + r) >> 1;
			if(mid * mid <= m) l = mid;
			else r = mid;
		}
		ans += (l + 1) / 2; // 只取奇数 
	}
	cout << ans;
	return 0;
}

 D Takahashi the Wall Breaker(破墙者)

【题目链接】

原题链接:D - Takahashi the Wall Breaker

【考点】

广度优先搜索bfs

【题目大意】

需要从起点(A, B)  沿着道路 "." 到达鱼店 (C, D),"#" 是墙壁,不过我们可以向前踢,向前踢有两种效果,1、可以向前两步、2、前方的墙壁倒塌可以通过,我们需要找到起点到鱼店所需最少向前踢次数。

【解析】

思路是使用广度优先搜索(BFS)算法来遍历所有可能的移动路径,同时记录到达每个单元格所需的最少前踢次数。在广搜中使用双端队列,将可前进的道路放到对头,需要前踢的放到队尾,同时记录前踢次数赋值到 vis 数组中代表到当前位置的最少前踢次数。

【难度】

GESP六级

【代码参考】

#include<bits/stdc++.h>
using namespace std;

const int N = 1005;
char mp[N][N];
int vis[N][N], h, w, sx, sy, tx, ty;
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

struct node{
	int x, y, d; // 位置和破墙数 
};

void bfs(){ // 广搜 
	deque<node> q; // 双端队列 
	q.push_back({sx, sy, 0});
	while(!q.empty()){
		node next = q.front();
		q.pop_front();
		if(vis[next.x][next.y] != -1) continue; // 已经走过,现在不可能是最优 
		vis[next.x][next.y] = next.d; // 记录每个位置的最优破墙数 
		for(int i = 0; i < 4; i++){ // 方向 
			for(int j = 1; j <= 2; j++){ // 前进步数 
				int x = next.x + dir[i][0] * j, y = next.y + dir[i][1] * j;
				if(x < 1 || y < 1 || x > h || y > w) continue;
				if(j == 1 && mp[x][y] == '.'){ // 走一步且是路径 
					q.push_front({x, y, next.d});
				}
				else if(j == 2 || mp[x][y]){ // 走两步要破墙 
					q.push_back({x, y, next.d + 1});
				}
			}
			
		}
	}
} 

int main(){
	cin >> h >> w;
	for(int i = 1; i <= h; i++){
		for(int j = 1; j <= w; j++){
			cin >> mp[i][j];
			vis[i][j] = -1;
		}
	}
	cin >> sx >> sy >> tx >> ty;
	bfs();
	cout << vis[tx][ty];
	
	return 0;
}




 E Ringo's Favorite Numbers 3(喜爱数字 3)

【题目链接】

原题链接:​​​​​​​E - Ringo's Favorite Numbers 3

【考点】

二分查找、素数筛

【题目大意】

400 数的定义:

  1. 条件一:一个正整数 N 要有恰好 2 个不同的质数因子。例如,36 = 2×2×3×3,它的质数因子是 2 和 3,满足有 2 个不同的质数因子;而 60 = 2×2×3×5,它的质数因子是 23 和 5,不满Q足该条件。

  2. 条件二:对于 N 的每个质因数 pp 整除 N 的次数是偶数次。用更正式的数学语言描述就是,存在最大的非负整数 k,使得 p^k 能整除 N,且 k 是偶数。例如,对于 36 = 2×2×3×3,质因数 2 整除 36 的次数是 2 次(2^2 能整除 36),质因数 3 整除 36 的次数也是 2 次(3^2 能整除 36),满足该条件;而对于 20 = 2×2×5,质因数 2 整除 20 的次数是 2 次,但质因数 5 整除 20 的次数是 1 次,不满足该条件。

同时满足以上两个条件的正整数 N 就是 400 数。

【解析】

使用素数筛筛选 10^6 内所有素数,并记录有多少不同的素数可以筛掉的合数,再统计有多少合数被筛的次数恰好为 2。最好再通过二分查找找到小于等于询问数的400数。

【难度】

GESP五级

【代码参考】

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
int q, prime[N], vis[N], k;
long long ans[N];

int main(){
	for(int i = 2; i <= 1000000; i++){ // 质数筛(埃拉托斯特尼筛) 
		if(vis[i]) continue; // 不是质数 
		for(int j = i*2; j <= 1000000; j += i){
			vis[j] = 1;
			prime[j]++; // 记录有多少不同质数个数 
		}
		prime[i]++;
	}
	for(int i = 2; i <= 1000000; i++){
		if(prime[i] == 2){ // 恰好为 2 
			ans[k++] = 1ll * i * i; // 记录该数的平方 
		}
	}
	cin >> q;
	while(q--){
		long long x;
		cin >> x;
		int l = 0, r = k;
		while(l + 1 != r){ // 二分查找 
			int mid = (l + r) >> 1;
			if(ans[mid] <= x) l = mid;
			else r = mid;
		}
		cout << ans[l] << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值