A 握手问题
1204
B 小球反弹
设x速度是15,y速度是17;
这里直接令 vx = dx的值,vy = dy
设x轴上走了p个来回,y轴上走了q个来回
小球经过碰撞回到原点 可得等式
v
x
⋅
t
=
2
⋅
p
⋅
x
vx \cdot t = 2 \cdot p \cdot x
vx⋅t=2⋅p⋅x
v
y
⋅
t
=
2
⋅
q
⋅
y
vy \cdot t = 2 \cdot q \cdot y
vy⋅t=2⋅q⋅y
现在知道x,y,可以求出p,q的比值
p
q
=
v
x
⋅
y
v
y
⋅
x
\frac{p}{q} = \frac{vx \cdot {y}}{vy \cdot {x}}
qp=vy⋅xvx⋅y
知道了比值,我们就可以给p,q赋值计算了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
// 定义一个求最大公约数的函数
int gcd(int a,int b)
{
// 使用欧几里得算法
return b ? gcd(b,a % b) : a;
}
int main()
{
// 定义两个整数x和y
int x = 343720 , y = 233333;
// 定义两个方向dx和dy
int dx = 15 , dy = 17;
// 计算p和q,其中p是dx和y的乘积,q是dy和x的乘积
int p =dx * y, q = dy * x;
// 使用gcd函数计算p和q的最大公约数d
int d = gcd(p,q);
// 将p和q都除以d,得到它们的最简形式
p /= d;
q /= d;
// 输出p和q的最简形式,格式为p/q
cout << p << "/" << q << endl;
// 计算t,它是2 * p * x / dx的值
int t = 2 * p * x / dx;
// 输出t
cout << t << endl;
// 计算dist,它是t和sqrt(dx * dx + dy * dy)的乘积
double dist = t * sqrt(dx * dx + dy * dy);
// 输出dist,保留两位小数
printf("%.2f\n",dist);
return 0;
}
C 好数
暴力模拟即可
#include<iostream>
#include<algorithm>
using namespace std;
int cnt = 0; // 初始化计数器为0
void handle(int x) {
for(int i = 1; i <= x; i++) { // 遍历从1到x的所有整数
string h = to_string(i); // 将当前整数转换为字符串
reverse(h.begin(),h.end()); // 反转字符串
bool flag = true; // 初始化标志位为true
for(int j = 0; j < h.size(); j++) { // 遍历反转后的字符串的每一位
int idx = j + 1; // 当前位的索引(从1开始)
int bit = h[j] - '0'; // 当前位的数字
if(idx % 2 == 0 ? bit % 2 != 0 : bit % 2 != 1) flag = false;
// 如果索引是偶数但数字是奇数
// 或索引是奇数但数字是偶数
//设置标志位为false
}
if(flag) cnt++; // 如果标志位仍为true,计数器加1
}
}
int main() {
int x; // 定义输入的整数x
cin >> x; // 从标准输入读取x
handle(x); // 调用handle函数处理x
cout << cnt; // 输出计数器的值
return 0;
}
D R格式
模拟即可,注意需要开高精度,如果是时间紧的话可以回头再来开
这里有把小数点忽略然后当成大数来计算,注意最后处理进位的时候
如果进位之后再产生进位,也要进行考虑,比如 99.6 进位之后是 100
所以判断的时候应该写一个循环
#include<bits/stdc++.h>
using namespace std;
// 定义乘法函数,将大数A与小数b相乘
vector<int> mul(vector<int> &A, int b) {
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i++) {
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10); // 将结果的每一位添加到C中
t /= 10; // 处理进位
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); // 删除前导零
return C;
}
int main() {
int n;
cin >> n;
string s;
cin >> s;
reverse(s.begin(),s.end()); // 反转字符串,方便处理
vector<int> num;
int pos = -1;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '.') pos = i - 1; // 记录小数点的位置
else num.push_back(s[i] - '0'); // 将数字添加到num中
}
while(n--) num = mul(num, 2); // 执行乘法操作
int k = pos;
if(pos != -1) {
if(num[pos] >= 5) num[pos + 1]++; // 处理四舍五入
pos++;
while(num[pos] >= 10) { // 处理进位
num[pos] -= 10;
num[pos + 1]++;
pos++;
}
}
for(int i = num.size() - 1; i > k; i--) cout << num[i]; // 输出结果
return 0;
}
E 宝石组合
根据算数基本定理可以化简
最后化简的S = gcd(ha,hb,hc)
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
vector<int> vd[N], cnt[N];
int n;
// 预处理出每个数的约数
void init() {
for(int i=1; i<=100000; i++)
for(int j=i; j<=100000; j+=i)
vd[j].push_back(i);
}
int main() {
scanf("%d", &n);
vector<int> a(n+1);
init(); // 初始化
for(int i=1; i<=n; i++)
cin >> a[i];
// 对数组进行排序
sort(next(a.begin()), a.end());
// 对每个数的约数进行计数
for(int i=1; i<=n; i++)
for(auto d : vd[a[i]])
cnt[d].push_back(a[i]);
// 找出可以作为三个数的最大公约数的数
int res=0;
for(int i=N; i>=0; i--) {
if(cnt[i].size() >= 3) {
res = i;
break;
}
}
// 打印出可以被最大公约数整除的前三个数
for(int i=0; i<3; i++)
printf("%d ", cnt[res][i]);
return 0;
}
F 数字接龙
简单的搜索,只是多加了几个判断
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef long long ll;
#define int long long
const int N = 110;
int n, k;
struct node
{
int nx;
int ny;
int dir;
};
int g[N][N];
bool st[N][N];
int dx[] = { -1,-1,0,1,1,1,0,-1 };
int dy[] = { 0,1,1,1,0,-1,-1,-1 };
vector<int> ans;
void dfs(int sx, int sy, int now, vector<int> path)
{
if(!ans.empty())return;
if (sx == n - 1 && sy == n - 1)
{
if (path.size() == n * n - 1)
{
ans = path;
}
return;
}
now %= k;
st[sx][sy] = true;
for (int i = 0; i < 8; i++)
{
int nx = sx + dx[i];
int ny = sy + dy[i];
if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
if (st[nx][ny]) continue;
if (g[nx][ny] == (now + 1) % k)
{
if(i == 0)
{
if(st[sx - 1][sy - 1]&&st[sx - 1][sy+1])continue;
}
else if (i == 1)
{
if (st[sx - 1][sy] && st[sx][sy + 1]) continue;
}
else if(i == 2)
{
if(st[sx - 1][sy + 1]&&st[sx + 1][sy + 1])continue;
}
else if (i == 3)
{
if (st[sx + 1][sy] && st[sx][sy + 1]) continue;
}
else if (i == 4)
{
if (st[sx + 1][sy + 1] && st[sx + 1][sy - 1]) continue;
}
else if (i == 5)
{
if (st[sx + 1][sy] && st[sx][sy - 1]) continue;
}
else if (i == 6)
{
if (st[sx - 1][sy - 1] && st[sx + 1][sy - 1]) continue;
}
else if (i == 7)
{
if (st[sx - 1][sy] && st[sx][sy - 1]) continue;
}
st[nx][ny] = true;
path.push_back(i);
dfs(nx, ny, (now + 1) % k, path);
path.pop_back();
st[nx][ny] = false;
}
}
st[sx][sy] = false;
return;
}
signed main()
{
cin >> n >> k;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
cin >> g[i][j];
}
}
vector<int> path;
if (g[0][0] != 0) {
cout << -1 << '\n';
return 0;
}
st[0][0] = true;
dfs(0, 0, g[0][0],{});
if(ans.size() == 0)
{
cout<<"-1"<<endl;
return 0;
}
else{
for(int i=0;i<ans.size();i++)
{
cout<<ans[i];
}
}
return 0;
return 0;
}
G 爬山
很容易就想到优先队列,但是这么写的错误的。
理论上来说最完美的解法就是纯暴力因为实际上是没有规律可循的,所以在这个时间复杂度下
可以说这个题目是无解的
如果是纯暴力的方法,时间复杂度将远超
(
p
+
q
)
n
{(p+q)}^n
(p+q)n
是无解的
贪心方法的错误数据如下
爬山这题有人提出了同差值时优先偶数的做法,以通过以下用例:
2 1 1
48 49
正确方法是 48 开根号 为 6
49 除 2 为 24
最小为30
很可惜,该做法依然是错误的,这是一组反例:
2 1 3
35 36
在这个用例中,你必须先对35开根,然后对36除以二3次。
有人提出了先进行所有开根操作再进行除以二操作,按操作前后差值从大到小贪心进行,差值相同时优先选择较小数开根的做法,但可惜依然是错误的,只需对上述用例稍作修改即可:
2 1 3
35 39
事实上,第二个数取36~39的范围内的任何数,你都必须先对35开根,然后对该数除以二3次。
所以不用深究,直接优先队列就行
#include<iostream>
#include<queue>
#include<math.h>
using namespace std;
priority_queue<int,vector<int>,less<int> >qe; // 定义一个优先队列
int main()
{
int n,p,q;
cin>>n>>p>>q;
int a;
for(int i=0;i<n;i++) // 读入n个数
{
cin>>a;
qe.push(a); // 将数放入优先队列中
}
long long sum=0;
while(p>0||q>0) // 当p或q大于0时,继续循环
{
a=qe.top(); // 取出队列中的最大值
qe.pop(); // 删除队列中的最大值
if(q==0) // 如果q等于0,那么只能进行平方根操作
{
a=sqrt(a);
p--;
qe.push(a);
}
else if(p==0) // 如果p等于0,那么只能进行除以2的操作
{
a/=2;
q--;
qe.push(a);
}
else // 如果p和q都大于0,那么选择使a变小的操作
{
if(fabs(a-a/2)<fabs(a-sqrt(a))) // 如果除以2后的a比平方根后的a小,那么选择除以2的操作
{
a=sqrt(a);
p--;
qe.push(a);
}
else // 否则,选择平方根的操作
{
a/=2;
q--;
qe.push(a);
}
}
}
int n1=qe.size();
for(int i=0;i<n1;i++) // 计算队列中所有数的和
{
a=qe.top();
sum+=a;
qe.pop();
}
cout<<sum; // 输出和
return 0;
}
H 拔河
注意所有人可以不全上
预处理所有前缀和然后暴力即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int>pii;
#define N 10100
int s[N],a[N];
signed main(){
int n;
cin>>n;
vector<pii>v;
for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
v.push_back({s[j]-s[i-1],i});
}
}
sort(v.begin(),v.end());
int ans=1e18;
for(int i=0;i<v.size()-1;i++){
if(v[i].second!=v[i+1].second) ans=min(ans,v[i+1].first-v[i].first);
}
cout<<ans<<endl;
return 0 ;
}
最后附上蓝桥杯题目自测网站
https://www.dotcpp.com/oj/problemset.php?page=89