算法继续刷起-2025年09月26日
1. 现在需要在坐标平面上以某一点 C 为圆心画一个圆,且该圆心必须位于坐标轴上。
请你找到一个最小的半径r,使得这圆能够覆盖不少于[n/2]个给定点,并输出这个最小半径。
【名词解释】
坐标轴:包含x轴和y轴。x 轴表示形如(x,0)的所有点;y轴表示形如(0,y)的所有点。
覆盖:若点 P 到圆心 c 的欧氏距离不超过圆的半径,则称该圆覆盖点 P。
#include<bits/stdc++.h>
using namespace std;
vector<pair<int,int>> points;
int n;
bool check(double mid){auto get = [&](int mode){vector<pair<double,int>> ans;for(auto p:points){if(mode == 0){if(fabs(p.second)>mid) continue;double d = sqrt(mid*mid - p.second*p.second);ans.emplace_back(p.first - d, 1);ans.emplace_back(p.first + d, -1);}else{if(fabs(p.first)>mid) continue;double d = sqrt(mid*mid - p.first*p.first);ans.emplace_back(p.second -d,1);ans.emplace_back(p.second + d,-1);}}sort(ans.begin(),ans.end(),[](const pair<double,int>& p1,const pair<double,int>& p2){if(p1.first == p2.first) return p1.second < p2.second;else return p1.first<p2.first;});int count =0;for(auto p:ans){count += p.second;if(count>=(n+1)/2) return true;}return false;};return get(0)||get(1);
}
int main(){cin>>n;points.resize(n);for(int i=0;i<n;i++){cin>>points[i].first>>points[i].second;}double lo = 0;double hi = 2e5;for(int i=0;i<50;i++){double mid = (lo + hi)/2;if(check(mid)) hi = mid;else lo = mid;}cout<<fixed<<setprecision(6)<<hi<<endl;return 0;
}
2. 给出一个长度为 n 的序列 a1,a2,a3…an,按以下规则输出序列的中位数:
- 若序列长度为奇数,中位数是升序排序后中间的数字。
- 若序列长度为偶数:
- 升序排序后,中间两数字 x=y 时,输出任意一个;
- 升序排序后,中间两数字 x=y 时,输出 min(x,y)。
- 输出中位数 midx 后,该数从序列消失,重复步骤直至序列元素全部输出。
#include<bits/stdc++.h>
using namespace std;
int main(){int n;cin>>n;vector<int> nums(n);for(int i=0;i<n;i++)cin>>nums[i];sort(nums.begin(),nums.end());vector<int> ans;for(int i = (n-1)/2;i>=0;i--){ans.push_back(nums[i]);if(2*i == n-1) continue;ans.push_back(nums[n-1-i]);}for(int i=0;i<n;i++){if(i)cout<<" ";cout<<ans[i];}return 0;
}
3. 任何一个数 n 都可以拆成若干项不同的、由 2 的次幂和 3 的次幂相乘之和,即 n=2a1×3b1+2a2×3b2+⋯+2am×3bm 且 2ai3bi=2aj3bj (1≤i<j≤m) 。给定整数 n,找到长度为 m 的序列 a1,a2,⋯,am 和 b1,b2,⋯,bm 满足方程,并按由大到小顺序依次输出。
#include<bits/stdc++.h>
using namespace std;
int main(){int t;cin>>t;while(t--){int n;cin>>n;vector<int> ans;while(n){int sum=0;int factor=1;while(factor*2<=n){factor=factor*2;}ans.push_back(factor);n -= factor;}cout<<ans.size()<<endl;for(int i=0;i<ans.size();i++){if(i)cout<<" ";cout<<ans[i];}cout<<endl;}return 0;
}
4. 小强最近在研究围棋,他希望有一个程序能告诉他一步之内,有哪些位置可以直接吃掉别人的棋子,吃几个。围棋可以在围住别人的情况下,吃掉别人的棋子。标准围棋的棋盘是19×19的,但小强只是想研究围棋的规则,故假定棋盘大小为n×n。
#include<bits/stdc++.h>
using namespace std;
int n;
vector<vector<char>> mat;
vector<vector<bool>> vit;
int main(){cin>>n;mat.resize(n,vector<char>(n));vit.resize(n,vector<bool>(n));for(int i=0;i<n;i++){for(int j=0;j<n;j++){cin>>mat[i][j];}}int mx[4] = {0,0,1,-1};int my[4] = {1,-1,0,0};function<int(int,int)> f = [&](int x,int y){int ans=mat[x][y] == 'x';bool isall = true;bool iscan = false;for(int i=0;i<4;i++){int x_ = x + mx[i];int y_ = y + my[i];if(x_>=0 && y_>=0 && x_<n && y_<n && !vit[x_][y_]){if(mat[x_][y_] == '.') return -1;else if(mat[x_][y_] == 'o') continue;else{iscan = true;vit[x_][y_]=true;int res = f(x_,y_);if(res!=-1){ans += res;isall = false;}}}}if(isall && iscan){return -1;}else{return ans;}};vector<vector<int>> ans;for(int i=0;i<n;i++){for(int j=0;j<n;j++){if(mat[i][j] == '.'){vit[i][j]=true;int res = f(i,j);if(res>0)ans.push_back({i+1,j+1,res});}}}cout<<ans.size()<<endl;for(int i=0;i<ans.size();i++){cout<<ans[i][0]<<" "<<ans[i][1]<<" "<<ans[i][2]<<endl;}return 0;
}
5. 牛牛给出了一个关于未知量 x
的多项式。这个多项式以字符串的形式表示,它由若干个形如 (x−d)
或 (x+d)
的括号表达式相乘构成,其中 d
是一个 1 到 9 之间的数字字符。牛牛想知道,当这个多项式完全展开后,x
的一次项(即 x^1
项)的系数是多少?请计算这个系数,由于答案可能很大,请将答案对 10007
取模后输出。
#include<bits/stdc++.h>
using namespace std;
int main(){string s;cin>>s;vector<int> nums;auto split = [&](){int n = s.size();int factor = 1;int num=0;for(int i=0;i<n;i++){if(s[i] == 'x'||s[i] == '(') continue;else if(s[i] == '-'){factor = -1;}else if(s[i] == '+'){factor = 1;}else if(isdigit(s[i])){num = num * 10 + s[i] - '0';}else{nums.push_back(num*factor);num = 0;}}};int mod = 10007;auto quickmi = [&](int value,int m){int ans = 1;int factor = value;while(m){if(m&1)ans = (ans * factor)%mod;factor = (factor * factor)%mod;m>>=1;}return ans;};split();int res = 1;for(auto c:nums){res = (res * c)%mod;}int total = 0;for(auto c:nums){total = (total + (res * quickmi(c,mod-2))%mod)%mod;}cout<<total<<endl;return 0;
}
6. 给定一个整数,请你判断它是否可以写成4个质数之和。若可以,请输出任意一种方案;否则输出-1。
#include <iostream>
#include <cmath>
using namespace std;bool is_prime(long long x) {if (x < 2) return false;if (x == 2) return true;if (x % 2 == 0) return false;for (long long i = 3; i * i <= x; i += 2) {if (x % i == 0) return false;}return true;
}int main() {int t;cin >> t;while (t--) {long long n;cin >> n;if (n % 2 == 0) {long long m = n - 4;for (long long p = 2; ; p++) {if (is_prime(p) && is_prime(m - p)) {cout << "2 2 " << p << " " << m - p << endl;break;}}} else {long long m = n - 5;for (long long p = 2; ; p++) {if (is_prime(p) && is_prime(m - p)) {cout << "2 3 " << p << " " << m - p << endl;break;}}}}return 0;
}
7. 小红有一个数组,她每次可以让两个相邻的数字一起加一,她想知道把数组变成左右对称的最小操作次数。
左右对称的意思是将数组整体翻转后与原数组一致,例如:{1,2,3,3,2,1},{4,0,4}都是左右对称的,而{8,1,0,9,7,5},{9,2,2,7,6,8}都不是左右对称的。
#include<bits/stdc++.h>
using namespace std;
int main(){int n;cin>>n;vector<int> nums(n);for(int i=0;i<n;i++) cin>>nums[i];int left = 0, right = n-1;int count = 0;while(left < right){if(nums[left]!=nums[right]){if(left == right - 1){cout<<-1<<endl;return 0;}else{if(nums[left] > nums[right]){count += nums[left] - nums[right];nums[right-1] += nums[left] - nums[right];nums[right] = nums[left];}else{count += nums[right] - nums[left];nums[left+1] += nums[right] - nums[left];nums[left] = nums[right];}}}left++;right--;}cout<<count<<endl;return 0;
}
8. 给出一个长度为n的序列a1,a2,…,n,求取出k个不同的区间,要求满足取出区间的区间和是t的倍数,求它们的区间和相加最大是多少?
一个区间的区间和即里面所有数相加,例如a=[4,3,5],区间[1,2]的和为7,区间{1,3]的和为12。
保证至少存在k个合法的区间。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){int n,k,t;cin>>n>>k>>t;vector<int> nums(n);for(int i=0;i<n;i++) cin>>nums[i];vector<ll> pre(n+1);for(int i=1;i<=n;i++){pre[i] = pre[i-1] + nums[i-1];}priority_queue<ll, vector<ll>, greater<ll>> pq;vector<vector<int>> mem(t);mem[0].push_back(0);for(int i=1;i<=n;i++){int m = pre[i]%t;for(int j=0;j<mem[m].size();j++){if(pq.size()>=k && pre[i]-pre[mem[m][j]]>pq.top()){pq.pop();}pq.push(pre[i]-pre[mem[m][j]]);}mem[m].push_back(i);}ll ans = 0;while(!pq.empty()){ans += pq.top();pq.pop();}cout<<ans<<endl;return 0;
}