zoukankan      html  css  js  c++  java
  • Codeforces Round #608 (Div. 2) 题解

    Codeforces Round #608 (Div. 2) 题解

    前言

    题目链接:仅仅只是为了方便以题目作为关键字能查找到我的题解而已(逃

    Codeforces 1271A

    Codeforces 1271B

    Codeforces 1271C

    Codeforces 1271D

    Codeforces 1271E

    重要:没有F的题解,想看F题题解的神仙们可以走了

    A. Suits

    题意

    给你(a)条领带,(b)条围巾、(c)件背心、(d)件夹克,有以下两种套装:

    • 一条领带、一件夹克,花费(e)

    • 一条围巾、一件背心、一件夹克,花费(f)

    求出最多可以卖多少钱(不能单卖)。(奸商)

    做法

    依题意可得:

    假如有(i)(e)元的套装,那么就是价格是(i imes e + min { d-i, b, c } imes f)元,枚举即可(注意 (i), (d-i), (b), (c) 中不能出现负数)。

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    int a,b,c,d,e,f,ans;
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>a>>b>>c>>d>>e>>f;
        for(int i=0;i<=min(a,d);i++){//数据范围小,直接暴力枚举
            ans=max(ans,i*e+min((d-i),min(b,c))*f);
        }
        cout<<ans<<endl;
    
        return 0;
    }
    

    B. Blocks

    FST的我真的是太菜了

    题意

    给你一排(n)个方块,每个方块有黑白两种颜色,每次操作可以反转两个相邻的方块的颜色,问能否(3n)次数内反转成一整排都是同一种颜色。

    做法

    假设序列反转成白色,那么从前到后跑一遍,如果当前方块不是白色就反转它和它后边的方块,最后一个方块如果跑完操作完是白色就OK。黑色同理,假设序列反转成黑色,那么从前到后跑一遍,如果当前方块不是黑色就反转它和它后边的方块,最后一个方块如果跑完操作完是黑色就OK。最后如果都不可以就输出(-1)了。

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    int n;
    char s[205];
    vector<int> op;
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>n;
        cin>>s+1;
        //假设全是白色:
        for(int i=1;i<n;i++){
            if(s[i]=='B'){
                s[i]='W';
                s[i+1]=s[i+1]=='W'?'B':'W';
                op.push_back(i);
            }
        }
        //判断最后一个方块:
        if(s[n]=='W'){
            cout<<op.size()<<endl;
            for(int i=0;i<op.size();i++){
                cout<<op[i]<<' ';
            }
            cout<<endl;
            return 0;
        }
        //假设全是黑色:(此时可以直接再操作同一个序列)
        for(int i=1;i<n;i++){
            if(s[i]=='W'){
                s[i]='B';
                s[i+1]=s[i+1]=='W'?'B':'W';
                op.push_back(i);
            }
        }
        //判断最后一个方块
        if(s[n]=='B'){
            cout<<op.size()<<endl;
            for(int i=0;i<op.size();i++){
                cout<<op[i]<<' ';
            }
            cout<<endl;
            return 0;
        }
        cout<<-1<<endl;
    
        return 0;
    }
    

    C. Shawarma Tent

    比B简单

    题意

    给你一个平面直角坐标系(刚刚数学课学过诶),之后给你一座学校和(n)个学生的坐标(都是整点),问你在一个不同于学校的整点上建一个买Shawarma的帐篷,如果学生从学校到家的某一条神奇路径上经过就会买(当消费者傻子吗),问你最多会有几个学生买,和此时帐篷的坐标(任意一种坐标即可)(奸商)

    注:整点指横坐标、纵坐标都是整数的点。神奇路径是只能上下左右移动(平行于横轴或纵轴)的两点间的最短路径(长度就是两点间的曼哈顿距离)(两点间可能有多条)。

    做法

    显然的,距离学校越近,就会有越多学生从帐篷经过,所以只要枚举学校上下左右的四个点看哪个最优就可以了。

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,sx,sy;
    int x[200005],y[200005];
    int l,r,u,d;
    //l, r, u, d 分别表示左右上下的帐篷经过的学生个数
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>n>>sx>>sy;
        for(int i=1;i<=n;i++){
            cin>>x[i]>>y[i];
            if(x[i]>sx)r++;
            if(x[i]<sx)l++;
            if(y[i]>sy)u++;
            if(y[i]<sy)d++;
            //对于经过帐篷的学生计数
        }
        if(r>=l&&r>=r&&r>=u&&r>=d){
            cout<<r<<endl;
            cout<<sx+1<<' '<<sy<<endl;
        }else
        if(l>=l&&l>=r&&l>=u&&l>=d){
            cout<<l<<endl;
            cout<<sx-1<<' '<<sy<<endl;
        }else
        if(u>=l&&u>=r&&u>=u&&u>=d){
            cout<<u<<endl;
            cout<<sx<<' '<<sy+1<<endl;
        }else
        if(d>=l&&d>=r&&d>=u&&d>=d){
            cout<<d<<endl;
            cout<<sx<<' '<<sy-1<<endl;
        }
        //这里的u>=u之类只是方便copy&paste罢了
    
        return 0;
    }
    

    D. Portals

    题面好长啊,真的不想翻译

    题意

    你要攻下(n)座城市。一开始你有(k)个士兵。攻下第(i)个城市,你需要(a_i)个士兵(进攻时不损失士兵),攻下后你会抓(b_i)个壮丁扩充你的队伍,攻下后你可以派一个士兵来防守,防守会使得你的分数增加(c_i),损失一个士兵。防守有两种方式:

    • 你可以防守你所在的第(i)个城市

    • (m)个单向的传送门,从(u)(v),如果你在(u),可以派兵防守(v)(必须是直接被传送门连接的城市)

    你必须从第(1)座一直攻克到第(n)座城市,如果不能攻克全部城市,你就输了,输出(-1),如果能赢,求出最大的分数。

    做法

    贪心的做,计算(req_i = max { a_{i+1} , req_{i+1} - b_{i+1} } | req_n = 0)代表在第(i)个城市攻克并有(b_i)士兵加入后,你完成游戏最少需要的士兵。之后就会有部分士兵空出,第(i)个城市空出士兵个数记为(fr_i),然后用大根堆来分派士兵到城市就好了。

    此时,第(i)个城市的可以守卫它的最后一个城市记为(def_i),从(1)(i)的空闲士兵显然都可以守卫它(空闲士兵可以跟着你到下一个城市)。

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,k;
    int a[5005],b[5005],c[5005],fr[5005];
    vector<int> g[5005];//无用数组
    int def[5005],req[5005];
    priority_queue<pair<int,int> > pq;
    int ans;
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++){
            cin>>a[i]>>b[i]>>c[i];
            def[i]=i;
        }
        for(int i=1;i<=m;i++){
            int u,v;
            cin>>u>>v;
            g[u].push_back(v);//无用语句
            def[v]=max(def[v],u);
        }
        for(int i=n;i>=1;i--){
            req[i]=max(a[i+1],req[i+1]-b[i+1]);cerr<<i<<' '<<req[i]<<endl;
        }
        //计算req[i]
        int cur=k;
        for(int i=1;i<=n;i++){
            if(cur<a[i]){
                cout<<-1<<endl;
                return 0;
            }
            cur+=b[i];
        }
        //↑判断是否能赢↑
        cur=k;
        for(int i=1;i<=n;i++){
            cur+=b[i];
            fr[i]=cur-req[i];cur=req[i];
            pq.push(make_pair(c[i],i));
        }
        //计算fr[i],初始化以重量为第一关键字降序排列的堆
        while(!pq.empty()){
            int val=pq.top().first,x=pq.top().second;
            pq.pop();
            int y=def[x];
            while(!fr[y]&&y>0)y--;
            if(y==0)continue;
            fr[y]--;//贪心地选择最后一个能选的城市的空闲士兵
            ans+=val;
        }
        cout<<ans<<endl;
    
        return 0;
    }
    

    E. Common Number

    题意

    做到E的人应该都知道吧。。。而且题面很简短我就不写了(逃

    做法

    定义(k_i)为包含(i)的路径的个数。

    首先,奇数和偶数分开考虑,你会发现同一个(n),同为奇数或偶数时,(y)变大了(k_y)肯定变小,所以具有单调性,可以二分。

    我们再来看对于单个的数,如何计算包含它的路径条数:

    把路径的计算反过来想,可以得出在路径的反推中,只有偶数可以加一,而所有数都可以乘二。记录有多少个可以通过这种方式得到的数就可以了。但是这样太慢了,所以我们需要一个更快的方法:

    通过观察得出,乘二的次数相同时,从最小可达值(只乘过二)到最大可达值(每次乘二后都加一),之间的所有数都是可以达到的,那么我们只要计算最小值和最大值就好了,复杂度--。由于乘二肯定比加一增长得快,所以对于每一种乘以二的次数,把这个区间的长度加到路径条数就可以了。

    程序

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    ll n,k;
    
    bool check(ll m){
        ll l=m,r=m,res=0;
        if(!(m&1)){r++;}//当m是偶数时给r增加1
        for(int i=1;;i++){//其实i没有什么用
            res+=min(n,r)-l+1;//添加区间长度到返回值
            //for(int j=l;j<=min(r,n);j++)cerr<<j<<' ';
            l<<=1;
            r=(r<<1)+1;//计算下一个l和r
            if(l>n)break;//当l大于n时就没有计算的必要了,直接退出
            
        }//cerr<<endl;
        return res>=k;
    }
    
    int main(){
    
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
    
        cin>>n>>k;
        //for(int i=1;i<=n;i++)check(i);
        ll l=1,r=(n+1)/2,m,ans;//二分奇数
        while(l<=r){
            m=(l+r)>>1;
            if(check(2*m-1)){
                ans=2*m-1;
                l=m+1;
            }else{
                r=m-1;
            }
        }
        l=1;r=n/2;//二分偶数
        while(l<=r){
            m=(l+r)>>1;
            if(check(2*m)){
                ans=max(ans,2*m);//由于ans已经取了奇数的值,所以这里是max
                l=m+1;
            }else{
                r=m-1;
            }
        }
        cout<<ans<<endl;
    
        return 0;
    }
    

    结束语

    点个在看吧!

    很抱歉不会F题不能帮到部分人,所以我(逃

  • 相关阅读:
    又学到的2个小技巧
    CSS3 简写animation
    CSS3 区别Transform,Transition,Animation一句话
    纠错【2012年5月9日 JQuery跑马灯(文字无缝向上翻动)(自已封装的第三个插件)】
    jQuery计算选中的文本字数,并弹出一个层(插件四)
    html5Canvas绘制线条closePath();
    html5循环方式绘制矩形
    jQuery过滤not()与filter();
    javascript在firebug调试时用console.log
    jQuery插件在光标定位的地方插入文字(插件5)
  • 原文地址:https://www.cnblogs.com/BlahDuckling747/p/Codeforces-Round-608-Div-2-Ti-Jie.html
Copyright © 2011-2022 走看看