ACGO2024新春欢乐赛全题解
2024-02-18 08:12:39
发布于:浙江
ACGO2024新春欢乐赛全题解
T1:
思路:
题目要求通过复制魔法糖果堆可以获得的最多的糖果数量,可以使用优先队列使小的在前,每次使用最小的两个进行操作,直到最小的两个大于 为止。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,f,num,cnt;
priority_queue<int,vector<int>,greater<int> > q;
int main(){
    cin>>n>>f;
    while(n--) cin>>num,q.push(num);
    while(true){
        int a,b;
        a=q.top(),q.pop(),b=q.top(),q.pop();
        if(a+b<=f){
            q.push(a);
            q.push(a+b);
            cnt++;
        }
        else break;
    }
    cout<<cnt;
}
T2:
思路:
题意是长度为 的一块地方,每次能连续打扫 个地方,几次可以打扫完,而不是每打扫到已打扫过的地方就得断。
所以这题找规律就行,长度为 ,每次可以打扫连续的 个地方,那么 就行。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k;
string c;
int main(){
    cin>>n>>k>>c;
    cout<<((n%k>0)?(n/k+1):(n/k));
}
T3:
思路:
给你两个数,一直把大的减去小的直到其中一个等于  为止,注意不能暴力,会TLE。
每次可以把大的数一次性减到小于原来的小的数为止。
代码:
#include<bits/stdc++.h>
using namespace std;
int a,b,n,cnt;
int main(){
    cin>>a>>b;
    while(a>0 && b>0){
        if(a<b) swap(a,b);
        cnt=a/b;
        a-=cnt*b;
        n+=cnt;
    }
    cout<<n;
}
T4:
思路:
给你一个数列,每次可以选择 数排序并移到数列末尾,求最少几次可以使数列变成升序排列的。
这题不用什么复杂的计算。
我们设定一个变量 ,每次判断输入的数是否等于所在的位置就行,不是就把 ++,判断的位置要减去 ,因为前面有 个数已经被移到末尾了,最后输出 就行。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,cnt,num;
int main(){
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>num;
        if(num!=i+1-cnt) cnt++;
    }
    cout<<(cnt%k>0?cnt/k+1:cnt/k);
}
T5:
思路:
40pts:
使用优先队列让数字大的在前,每次每次让大的减去小的直到最大的两个相等为止。
最后输出 ( 为优先队列名称)就行。
100pts:
直接判断最大的两个数字是否相等可能会存在无法考虑的情况,如
4
2 2 3 3
可以写个函数判断队列内所有元素是否相等,全部相等返回-1,否则返回不相等的位置,然后在进行题目要求的操作就行。
输出同40pts的输出。
代码:
40pts:
#include<bits/stdc++.h>
using namespace std;
int n,num,cnt;
priority_queue <int,vector<int>,less<int> > q;
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>num,q.push(num);
    while(true){
        int a,b;
        a=q.top(),q.pop(),b=q.top(),q.pop();
        if(a==b){
            cnt=a;
            break;
        }else{
            q.push(a-b);
            q.push(b);
        }
    }
    cout<<cnt*n;
}
100pts:
#include<bits/stdc++.h>
using namespace std;
int n,num,cnt;
priority_queue <int,vector<int>,less<int> > q;
int f(priority_queue<int, vector<int>,less<int> >& q){
    vector<int> v,v2;
    int size=q.size();
    while(!q.empty()){
        int top=q.top();
        v.push_back(top),v2.push_back(top),q.pop();
    }
    for(int i=0;i<size;i++){
        q.push(v[i]);
    }
    auto it=unique(v.begin(),v.end());
    if(it-v.begin()==1) return -1;
    else{
        size=q.size();
        for(int i=0;i<size;i++){
            if(v2[i]!=v2[i+1]) return i;
        }
    }
}
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>num,q.push(num);
    while(true){
        int idxx=f(q);
        if(idxx==-1){
            cnt=q.top();
            break;
        }else{
            int m=q.top();
            for(int i=0;i<idxx;i++) q.pop();
            int a,b;
            a=q.top(),q.pop(),b=q.top(),q.pop();
            q.push(a-b);
            q.push(b);
            for(int i=0;i<idxx;i++) q.push(m);
        }
    }
    cout<<cnt*n;
}
T6:
思路:
这题就像是给你一排长短不齐大葱,问你怎么切使所有大葱一样长且切的部分最少,那必然是往短的切。
我们可以输入时更新所有数中的最小数,然后再遍历一遍所有数,把每个数和最小数的差加起来,最后输出。
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,min_=1000005,nums[55],cnt;
int main(){
    cin>>n;
    for(int i=0;i<n;i++) cin>>nums[i],min_=min(min_,nums[i]);
    for(int i=0;i<n;i++) cnt+=(nums[i]-min_);
    cout<<cnt;
}
T7:
思路:
这题要我们求赶跑年兽的最小需求,因为  个以上的年兽可以用  个金币一窝端一次性驱赶,所以可以分类讨论,年兽不小于  个用  个金币一次性驱赶,否则用  个金币逐个驱赶。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,cnt,num;
int main(){
    cin>>n>>k;
    while(n--){
        cin>>num;
        if(num>=k) cnt+=k;
        else cnt+=num;
    }
    cout<<cnt;
}
T8:
思路:
求输入最早的仅出现一次的数。
每次输入时把对应的标记数组的数增加,如果数为1则为第一次出现,标记出现的位置。
再遍历一遍输出出现最早的仅出现一次的数即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,num,nums[10005][2],first,second=114514;
int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>num,nums[num][0]++;
        if(nums[num][0]==1) nums[num][1]=i;
    }
    for(int i=1;i<=10000;i++){
        if(nums[i][0]==1){
            if(nums[i][1]<second) first=i,second=nums[num][1];
        }
    }
    cout<<first;
}
T9:
思路:
快乐值总共为 ,每个糖果最好的情况应该都是 ,结果应该是 ,注意因为糖果最多有 个,最后的结果应该是 。
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,s;
int main(){
    cin>>n>>s;
    n*=2;
    cout<<min((s/n),n/2+1);
}
T10:
思路:
题目要求 个是否可以两两配对并保证每一组的和相加均为奇数。
稍微想一下可以发现以下规律:
说白了就是奇数与偶数相加为奇数,偶数与偶数或奇数与奇数相加为偶数。
可以得出当输入的数中,偶数与奇数数量相等时,可以保证每一组的和相加均为奇数。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,num,a,b;
int main(){
    cin>>n;
    for(int i=0;i<n*2;i++){
        cin>>num;
        if(num&1) a++;
        else b++;
    }
    cout<<(a==b?"YES":"NO");
}
我的思路不一定是最优最正确的解法,只是希望让帮助各位更好的理解题意,部分的题解可能是题目的数据不够毒瘤强度不大,只是碰巧过了。
好了,ACGO2024新春欢乐赛全题解就到这里,下次见!
全部评论 6
关于T5,有个更方便的方法。
先考虑只有两个数,那答案便是一直拿小的去减大的,注意到这和辗转相除法是一致的,于是得到两个数的答案便是他们的gcd。n个数同理,求整体gcd即可,时间复杂度nlogV。2024-02-18 来自 天津
1是的,我写复杂了
2024-02-18 来自 浙江
0
orz
2024-02-18 来自 广东
0草T5我是O(n^2)
2024-02-18 来自 四川
0orz
2024-02-18 来自 四川
0古希腊掌管队列的神(bushi)
2024-02-18 来自 广东
0自顶
2024-02-18 来自 浙江
0



















有帮助,赞一个