其他分享
首页 > 其他分享> > ACM集训题(1)

ACM集训题(1)

作者:互联网


title: acm训练习题
author: Sun-Wind
date: June 15,2022

A

img
img
此题较为简单,主要考察了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

img
img
此题同样考察基本的语法知识

#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

img
img
根据题意进行结构体排序即可

#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

img
img
本题首先将题目所给的两个数的最大公约数求出
由于选择的是公共的质因数,所以所有的答案原则上都小于最大公约数
我们对最大公约数进行试除法筛出质因数即可
本题主要考察了数学方面的知识

#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

img
img
本题考察了记忆化搜索的知识
由于所有的宝箱数目较少,我们可以将宝箱进行状态压缩(为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

img
img
抽象化出一个数学问题是从一个数组中每次选K个不同的数,问最多能选几次
此题在思维方面确实不太好想,刚开始我用的是优先队列的做法,但是时间复杂度接近了N^2logN,最后只过了70%的点
正解是前缀和+二分
我们在输入的时候记录每一个数出现的次数,并且同时还要记录出现本次的数有多少个
img
为了便于理解,我画了一副图

如图的柱状图就是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;
}

标签:int,res,cin,long,ACM,include,集训,define
来源: https://www.cnblogs.com/Sun-Wind/p/16379504.html