中石大第39次CSP培训Week5题解

A.排队接水


Key:贪心

题目要求说要平均等待时间最短,也就是总等待时间最短。所以令接水需求最小的人排在前面,最大的排在后面。

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 2e5+10, MAX = 1e9, INF = -1e9;

    int n;
    PII a[N];
    double ans=0;

    void solve(){
        cin>>n;a[0]={0,0};
        for(int i=1;i<=n;i++)cin>>a[i].first,a[i].second=i;
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++)a[i].first+=a[i-1].first,cout<<a[i].second<<" ";
        cout<<endl;
        for(int i=1;i<=n;i++)ans+=a[i-1].first*1.0;
        printf("%.2lf",ans/n*1.0);
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

B.合并果子


Key:贪心+最小堆

每次合并剩余堆中最小的两堆

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 2e5+10, MAX = 1e9, INF = -1e9;

    int n;
    int e;
    int ans=0;
    Q q;


    void solve(){
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>e;
            q.push(e);
        }
        while(q.size()>=2){
            int a=q.top();q.pop();
            int b=q.top();q.pop();
            ans+=a+b;
            q.push(a+b);
        }
        cout<<ans<<endl;
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

C.平均分配


Key:排序

计算出小B和小C两种价格的差并排序,前n个给小B,剩余给小C

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 2e5+10, MAX = 1e9, INF = -1e9;

    int n;
    vector<PII> v(N); 
    int ans=0;

    bool cmp(PII x,PII y){
        if(x.first!=y.first)return x.first>y.first;
        else return x.second>y.second;
    }

    void solve(){
        cin>>n;
        for(int i=1;i<=2*n;i++)cin>>v[i].second;
        for(int i=1;i<=2*n;i++){
            cin>>v[i].first;
            v[i].first=v[i].second-v[i].first;
        }
        sort(v.begin()+1,v.begin()+2*n+1,cmp);
        for(int i=1;i<=n;i++)ans+=v[i].second;
        for(int i=n+1;i<=2*n;i++)ans+=v[i].second-v[i].first;
        
        
        cout<<ans<<endl;
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

D.第34次CSP认证第二题:矩阵重塑(其二)


Key:技巧—矩阵的一维压缩

重塑操作对于一维压缩的矩阵修改为 \(O(1)\),只需要修改 \(m\)\(n\)

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 1e4+10, MAX = 1e8, INF = -1e9;

    int a[N];
    int g[N][N];
    int m,n;
    int q;

    void f1(int x,int y){
        n=x;
        m=y;
    }

    void f2(){
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                g[i][j]=a[(j-1)*m+i];
            }
        }
        swap(m,n);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[(i-1)*m+j]=g[i][j];
            }
        }
    }

    void solve(){
        cin>>n>>m>>q;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>a[(i-1)*m+j];
            }
        }
        
        int op,x,y;
        while(q--){
            cin>>op>>x>>y;
            if(op==1)f1(x,y);
            else if(op==2)f2();
            else cout<<a[x*m+y+1]<<endl;//二维数组的一维压缩
        }
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

E.My Cow Ate My Homework S


Key:最小后缀数组+后缀和

逆向预处理出后缀和和最小值直接计算平均值

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 2e5+10, MAX = 1e9, INF = -1e9;

    int n;
    double a[N];
    double s[N];
    double lost[N];
    double ave[N];
    double top=-1;

    void solve(){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        lost[n+1]=MAX;s[n+1]=0;
        for(int i=n;i>=2;i--){
            lost[i]=min(lost[i+1],a[i]);
            s[i]=s[i+1]+a[i];
            if(i!=n)ave[i]=((s[i]-lost[i])/(n-i))*1.0,top=max(top,ave[i]);
           
        }
        for(int i=2;i<=n-1;i++){
            if(top==ave[i])cout<<i-1<<endl;
        }
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

F.第36次CSP认证第二题:梦境巡查


Key:前缀和+后缀最大数组

每次计算和的时候用前缀和优化,最后多出的代价就是原本的最大值和后缀中的最大值+ \(c\) ,预处理出后缀最大值即可优化到 \(O(n)\)

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 1e5+10, MAX = 1e8, INF = -1e9;

    int n;
    int a[N];
    int b[N];
    int c[N];
    int e=0;
    int suma=0;int sumb=0;

    void solve(){
        cin>>n;
        for(int i=0;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++)cin>>b[i];
        b[0]=0;
        for(int i=1;i<=n+1;i++){
            suma+=a[i-1];sumb+=b[i-1];
            c[i]=max(0ll,suma-sumb);
            e=max(e,c[i]);
        }
        stack<int> ans;
        for(int i=n+1;i>=1;i--){
            c[i]=max(c[i+1],c[i]);
            int x=max(e,c[i]+b[i-1]);
            x=min(suma,x);
            ans.push(x);
        }
        ans.pop();
        while(!ans.empty()){
            cout<<ans.top()<<" ";
            ans.pop();
        }
        return ;
    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }

G.怪物


Key:贪心,二分,排序

我们来想想贪心的策略,首先,我们很显然的可以想到一个解法:在有怪物地雷肯定是要引爆的。计算每一只怪物移动到附近地雷的代价(加上引爆代价),如果它小于等于这只怪物的生命值 \(h[i]\) ,那么我们就选择移动并引爆,否则直接敲死即可。但是,这样明显是错误的,我们不应该将怪物移动到地雷上就引爆,应该看看有没有其他怪物也要移动到这里,一起引爆,能省更多的钱,那么我们就需要定义一个数组 \(st\) 来表示这里是否已经有怪物了。至于为啥是小于等于 \(h[i]\) 呢,原因是你占一个地雷说不定可以让其他怪物更少花费便可以被杀死。而判断移动到附近地雷的代价,我们只要将 \(x\) 排序,使用 \(lower bound\) 即可。这种怪物处于中间(并且两边移动花费(包括引爆费用)相同,移动花费小于怪物生命值)的情况又怎么办呢?哦,我们应该将怪物的位置也进行排序,这样,前面的已经全部处理完了,我们只需要考虑后面的!

AC代码

    #include<bits/stdc++.h>
    #define endl '\n'
    #define int int long long
    #define pb push_back
    #define bs bitset
    #define val(a) (a<'a' ? (a-'A'+'a') : a)
    #define fast() ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr)
    using namespace std;

    typedef pair<char,int> PCI;
    typedef pair<int,int> PII;
    typedef pair<long long, long long> PLL;
    typedef priority_queue<int> PQ;
    typedef priority_queue<int, vector<int>, greater<int>> Q;
    const int N = 2e5+10, MAX = 1e18, INF = -1e18;

    int n,k;
    PII a[N];
    int x[N];
    PII moves[N];
    bool st[N];
    bool ben[N];
    int ans=0;

    void solve(){
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            cin>>a[i].first>>a[i].second;
        }
        for(int i=1;i<=k;i++){
            cin>>x[i];
        }
        sort(x+1,x+1+k);
        sort(a+1,a+1+n);
        
        x[0]=INF;x[k+1]=MAX;
        for(int i=1;i<=n;i++){
            int t=lower_bound(x,x+k+2,a[i].first)-x;
            int d1=abs(x[t]-a[i].first);
            int d2=abs(x[t-1]-a[i].first);
            if(d1<=d2){
                moves[i].first=t;
                moves[i].second=d1;
            }
            else{
                moves[i].first=t-1;
                moves[i].second=d2;
            }
            if(d1==d2)ben[i]=true;
        }
        for(int i=1;i<=n;i++){
            if(moves[i].second+1<=a[i].second){
                ans+=moves[i].second;
                if(ben[i]&&st[moves[i].first-1])continue;
                else st[moves[i].first]=true;
            }
            else ans+=a[i].second;
        }
          
        for(int i=1;i<=k;i++){
            if(st[i])ans++;
        }
        cout<<ans<<endl;
        return ;

    }

    signed main()
    {
        fast();
        
        int t=1;
        //cin>>t;
        while(t--){
            solve();
        }
        return 0;
    }
posted @ 2025-07-25 17:25  Oaths  阅读(56)  评论(0)    收藏  举报