随便写写
A
此题较为简单,主要考察了setprecision函数来输出小数
考察知识点:语法
#include<bits/stdc++.h>
#include<iomanip>
using namespace std;
#define int long long
#define endl '\n'
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
int p;
if(n % 2 == 1)
p = n / 2 + 1;
else p = n / 2;
cout << fixed << setprecision(10);
cout << (double)p / (double)n << endl;
return 0;
}
B
此题同样考察基本的语法知识
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 5;
int vis[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin >> n >> k;
int res = 0;
for(int i = 1; i <= n; ++i){
cin >> vis[i];
if(vis[i] >= k) res++;
}
cout << res << endl;
return 0;
}
C
根据题意进行结构体排序即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 5;
struct stu{
int id;
int order;
bool operator < (const stu p) const{
return order < p.order;
}
}stu[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n; i++){
stu[i].id = i;
cin >> stu[i].order;
}
sort(stu+1,stu+1+n);
for(int i = 1; i <= n-1; i++){
cout << stu[i].id << " ";
}
cout << stu[n].id << endl;
return 0;
}
D
本题首先将题目所给的两个数的最大公约数求出
由于选择的是公共的质因数,所以所有的答案原则上都小于最大公约数
我们对最大公约数进行试除法筛出质因数即可
本题主要考察了数学方面的知识
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int a,b;
cin >> a >> b;
int c = gcd(a,b);
int res = 0;
for(int i = 2; i <= c / i; i++){
if(c % i == 0)
{
res++;
while(c % i == 0){
c /= i;
}
}
}
if(c > 1) res++;
res++;
cout << res << endl;
return 0;
}
E
本题考察了记忆化搜索的知识
由于所有的宝箱数目较少,我们可以将宝箱进行状态压缩(为0表示未解锁,为1表示已解锁)
dfs表示搜到第key把钥匙时,此时宝箱的状态是state
把花费高的分支剪掉,当遍历到所有的宝箱都开启时就跳出
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e3 + 5;
int vec[N];
int v[N];
int n,m;
int res;
int dp[1 << 13];
int fac(int p){
if(p == 0) return 1;
else return 2 * fac(p-1);
}
void dfs(int key,int sta){
if(res > dp[sta]) return;
else dp[sta] = res;
if(sta == (1 << n) - 1) return;
if(key > m) return;
dfs(key+1,sta);
sta = sta | vec[key];
res += v[key];
dfs(key+1,sta);
res -= v[key];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
memset(dp,0x3f,sizeof(dp));
cin >> n >> m;
for(int i = 1; i <= m; i++){
int a,b;
cin >> a >> b;
v[i] = a;
int q = 0;
for(int j = 1;j <= b; j++){
int p;
cin >> p;
q = q + fac(p-1);
}
vec[i] = q;
// cout << vec[i] << endl;
}
dfs(1,0);
if(dp[(1 << n) - 1] == 0x3f3f3f3f3f3f3f3f) cout << "-1" << endl;
else cout << dp[(1 << n) - 1] << endl;
return 0;
}
F
抽象化出一个数学问题是从一个数组中每次选K个不同的数,问最多能选几次
此题在思维方面确实不太好想,刚开始我用的是优先队列的做法,但是时间复杂度接近了N^2logN,最后只过了70%的点
正解是前缀和+二分
我们在输入的时候记录每一个数出现的次数,并且同时还要记录出现本次的数有多少个
为了便于理解,我画了一副图
如图的柱状图就是mapp数组所对应的值
一个很显然的规律是,mapp数组一定是递减的(很好理解,相当于存在出现n次的数,必定也存在出现n-1次的数,以此类推)
并且mapp数组中不会出现重复的数
本题的一个难点是,如何正确的划分并理解mapp数组,如上图一所示
每一个红色都相当于此时选了K个数(黄色那个部分合起来相当于一个红色,相当于在1里面选第二个K时不够了,需要到2里面补充)
这个时候可能会有一个问题,在2黄色里面选的数也有可能在1的黄色里面,这样一个数组就会出现重复的数,这样显然是不符合逻辑的
现在我们要证明一个结论,上述的情况是完全可以避免的
虽然2的黄色里面可能会有重复数的情况,但是我们可以把这个重复的数和1红色里面的某个数交换,这样交换以后每个就都是合法的
(1的红色里不会重复,因为和此数相同的在1的黄色里,同样这样做有可能2的黄色会出现重复,但是由于在1中红色面积比黄色大,所以在1的红色中必然存在
正确可以交换的数,使得两种颜色中的数都合法)
前缀和便可以很好地利用这个结论
接下来我们二分答案可以找到符合条件最大地选择数量
如图二所示,绿色线即表示每个数组所选择的K数量,显然,2和3中的数都不够,那么我们就可以截取1的部分来填充2,3,利用上述的结论便能得到正确的答案
本题主要考察了前缀和+二分的知识,但是其中运用的数学思维还是不太容易能想出来的
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 3e5 + 5;
int show[N];
int sum[N];
int mapp[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
for(int i = 1; i <= n;i++){
int x;
cin >> x;
show[x]++;
mapp[show[x]]++;
}
for(int i = 1; i <= n;i++){
sum[i] = sum[i-1] + mapp[i];
}
for(int k = 1; k <= n;k++){
int ans = 0;
int left = 0,right = n;
int mid;
while(left < right){
mid = left + right + 1>> 1;
if(k * mid <= sum[mid]){
left = mid;
}
else{
right = mid - 1;
}
}
cout << left << endl;
}
return 0;
}