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 数的定义:
-
条件一:一个正整数
N
要有恰好2
个不同的质数因子。例如,36 = 2×2×3×3
,它的质数因子是2
和3
,满足有2
个不同的质数因子;而60 = 2×2×3×5
,它的质数因子是2
、3
和5
,不满Q足该条件。 -
条件二:对于
N
的每个质因数p
,p
整除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;
}