ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ACM集训题(1)

2022-06-15 19:02:17  阅读:149  来源: 互联网

标签:int res cin long ACM include 集训 define



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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有