Codeforces Round #477 (rated, Div. 2, based on VK Cup 2018 Round 3)

博主分享了参加Codeforces Round #477比赛的经历,探讨了A到D四道题目。A题采用暴力枚举解决;B题通过贪心策略解决;C题因忽视特殊情况导致错误,最终找到最优解法;D题初次尝试的贪心策略失败,调整后通过大数据和小数据分开处理的策略得以解决。

又有一段时间没打cf了,最近要找点强度,连一场找找感觉,做题时自信满满,然而在进击d题的过程中c题被hack了,导致分数--,还是好久没打手有点生了,细节考虑不周啊

A. Mind the Gap

思路:往时间表中插入事件,这就是一个典型的水题咯,暴力枚举初始时间和每件事发生后作为插入点

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 1e5+10;

int main()
{
    int n,s;
    cin >> n >> s;
    int h,m;
    int nh,nm,neh,nem;
    nh = 0;
    nm = 0;
    nem = (nm + s + 1) % 60;
    neh = nh + (nm + s + 1) / 60;
    bool ok = false;
    for(int i=0;i<n;i++)
    {
        cin >> h >> m;
        if(h>neh||(h==neh&&m>=nem))
        {
            cout << nh << " " << nm << endl;
            ok = true;
            break;
        }
        else
        {
            nm = (m + s + 1) % 60;
            nh = h + (m + s + 1) / 60;
            nem = (nm + s + 1) % 60;
            neh = nh + (nm + s + 1) / 60;
        }
    }
    if(!ok)
    {
        cout << nh << " " << nm << endl;
    }
    return 0;
}

B. Watering System

思路:堵最少的洞口使灌溉量达标,这个典型的贪心,每次堵最大洞判断即可

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 1e5+10;
const double eps = 1e-6;

int s[maxn];

int main()
{
    int n,A,B;
    ios::sync_with_stdio(false);
    cin >> n >> A >> B;
    double sum = 0.0;
    for(int i=0;i<n;i++)
    {
        cin >> s[i];
        sum += s[i];
    }
    double need = (double)(s[0] * A) / (double)(B);
    sort(s+1,s+n);
    int pos = n;
    //cout << need << " " << sum-eps << endl;
    if(need < sum - eps)
    {
        for(pos=n-1;pos>0;pos--)
        {
            sum -= s[pos];
            //cout << pos << "*" << sum << "*" << need-eps << endl;
            if(sum <= need + eps)
            {
                break;
            }
        }
    }
    cout << n - pos << endl;
    //cout << need << endl;
    return 0;
}

C. Stairs and Elevators

思路:寻找最快回家方案,这题如果纯暴力明显tle,那就需要计算方案,思路其实也挺清晰,就是四种,两侧最近电梯和两侧最近楼梯都尝试一遍,取最优值,然而这题的坑点就在于如果两人同一层楼的话,就不需要经过电梯和楼梯就能直接到,这里被hack确实是自己的疏漏

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 1e5+10;

int ll[maxn];
int ee[maxn];

int myabs(int k)
{
    if(k <0)
    {
        k *= (-1);
    }
    return k;
}

int main()
{
    ios::sync_with_stdio(false);
    //freopen("in.txt","r",stdin);
    int n,m,cl,ce,v;
    cin >> n >> m >> cl >> ce >> v;
    for(int i=0;i<cl;i++)
    {
        cin >> ll[i];
    }
    for(int i=0;i<ce;i++)
    {
        cin >> ee[i];
    }
    int q;
    cin >> q;
    while(q--)
    {
        int x1,y1,x2,y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if(y1 > y2)
        {
            int temp = y1;
            y1 = y2;
            y2 = temp;
            temp = x1;
            x1 = x2;
            x2 = temp;
        }
        if(x1 == x2)
        {
            cout << y2 - y1 << endl;
            continue;
        }
        int sum = 2e9 + 10;
        int pos = lower_bound(ee,ee+ce,y1)-ee;
        int pos2 = pos-1;
        int hh = (myabs(x1-x2) - 1) / v + 1;
        if(pos < ce)
        {
            if(ee[pos] < y2)
            {
                sum = y2 - y1 + hh;
                //con = false;
                //cout << "1*" << sum << endl;
            }
            else
            {
                int tempsum = ee[pos] - y2 + ee[pos] - y1 + hh;
                //cout << "2*" << tempsum << endl;
                if(tempsum < sum)
                {
                    sum = tempsum;
                }
            }
        }
        if(pos2 >= 0)
        {
            int tempsum = y2 - ee[pos2] + y1 - ee[pos2] + hh;
            //cout << "3*" << tempsum << endl;
            if(tempsum < sum)
            {
                sum = tempsum;
            }
        }
        pos = lower_bound(ll,ll+cl,y1)-ll;
        pos2 = pos-1;
        hh = myabs(x1-x2);
        if(pos < cl)
        {
            if(ll[pos] < y2)
            {
                int tempsum = y2 - y1 + hh;
                //cout << "4*" << tempsum << endl;
                if(tempsum < sum)
                {
                    sum = tempsum;
                }
                //con = false;
            }
            else
            {
                int tempsum = ll[pos] - y2 + ll[pos] - y1 + hh;
                //cout << "5*" << tempsum << endl;
                if(tempsum < sum)
                {
                    sum = tempsum;
                }
            }
        }
        if(pos2 >= 0)
        {
            int tempsum = y2 - ll[pos2] + y1 - ll[pos2] + hh;
            //cout << "6*" << tempsum << endl;
            if(tempsum < sum)
            {
                sum = tempsum;
            }
        }
        cout << sum << endl;
    }
    return 0;
}

D. Resource Distribution

思路:这题又是一个贪心,一开始的贪心策略是先处理大值,满足大值的情况下再处理小值,对于每次处理,暴力分的组数,采纳最小组数的结果

然而事实证明这种贪心策略是有漏洞的,由于整除性,完全可能小值占大位导致大值无处可占

于是想到统计每次占位的剩余值,保留最小剩余作为贪心策略,然而不好意思,维护剩余值的过程tle了

又想到只维护存在值,等结束后再统一处理,然而,有出问题了,存在大值占小位又wa了,无奈之下想出大数据直接贪心,小数据维护的玄学面向数据编程,成功过掉了这一题

当然,面上数据编程这样是不对的,本着学习而不是为了比赛的态度,重新研究了一波这题,正确的做法其实也不是很复杂,从前面的研究不难发现,之前的贪心策略过的数据特别多,只是少部分数据出了问题,那么就可以在原来贪心策略上进行改进

考虑到先贪心大数似乎没有足够的道理,而无论怎么贪心,贪心失败的结果也往往是一个数据占据了另一个数据本该有的位置,于是考虑到两次贪心,两个数各先贪心一次,若有成功方案即可

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>

using namespace std;

const int maxn = 3e5+10;

const double eps = 1e-6;

map<int,vector<int> > pos;
map<int,int> num;

vector<int> rere1,rere2;

bool ccin[maxn];
int cc[maxn];
int cc0[maxn];

int main()
{
    int n,x1,x2;
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    while(cin >> n >> x1 >> x2)
    {
        int re1,re2;
        bool rev = false;
        pos.clear();
        num.clear();
        rere1.clear();
        rere2.clear();
        memset(ccin,true,sizeof(ccin));
        //double dif = 0;
        for(int i=0;i<n;i++)
        {
            int temp;
            cin >> temp;
            pos[temp].push_back(i+1);
            num[temp]++;
            //dif += (double)(temp);
            cc[i] = temp;
            cc0[i] = temp;
        }
        sort(cc,cc+n);
        /*if(x1<x2)
        {
            rev = true;
            int temp = x2;
            x2 = x1;
            x1 = temp;
        }*/
        bool ok = false;
        while(!ok)
        {
            if(rev)
            {
                pos.clear();
                num.clear();
                rere1.clear();
                rere2.clear();
                memset(ccin,true,sizeof(ccin));
                pos.clear();
                num.clear();
                for(int i=0;i<n;i++)
                {
                    int temp = cc0[i];
                    pos[temp].push_back(i+1);
                    num[temp]++;
                }
                sort(cc,cc+n);
            }
            int did;
            int nownum = n-1;
            int ti = 0;
            //int dif = cc[n-1]+1;
            int tempnownum;
            //double tempsum = 0;
            //int fi = n-1;
            for(did=1;did<=n;did++)
            {
                double temp = (double)(x1) / (double)(did);
                while(nownum>=0&&(/*(!ccin[nownum])||*/(temp-eps <= (double)(cc[nownum]))))
                {
                    //cout << "&";
                    //if(ccin[nownum])
                    //{
                        ti++;
                        //tempsum += (double)(cc[nownum]);
                    //}
                    nownum--;
                }
                //cout << ti << "^^" << did << "^^"<< tempsum<< endl;
                //cout << ti << "*" << did << "*" << nownum <<endl;
                if(ti>=did)
                {
                    while(ti>did)
                    {
                        //tempsum -= (double)(cc[fi]);
                        //fi--;
                        ti--;
                    }
                    //double tempdif = 0;
                    ok = true;
                    /*for(int i=0,j=nownum+1;i<did;i++,j++)
                    {
                        tempdif += cc[j] - (int)(temp);
                  //      cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
                    }*/
                    //tempdif = tempsum - ceil(temp) * (double)(did);
                    //cout << tempdif <<  "&&" <<nownum << "&&" << did<< endl;
                    //if(tempdif < dif + eps)
                    //{
                        //dif = tempdif;
                        /*if(ok)
                        {
                            for(int i=0,j=tempnownum+1;i<re1;i++,j++)
                            {
                                int nowpos = cc[j];
                                rere1.clear();
                          //      cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
                                num[nowpos] ++;
                                ccin[j] = true;
                            }
                        }
                        else
                        {
                            ok = true;
                        }
                        for(int i=0,j=nownum+1;i<did;i++,j++)
                        {
                            int nowpos = cc[j];
                            rere1.push_back(pos[nowpos][num[nowpos]-1]);
                      //      cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
                            num[nowpos] --;
                            ccin[j] = false;
                        }*/
                        tempnownum = nownum;
                        re1 = did;
                    //}
                    /*if(n==4&&x1==12&&x2==11)
                    {
                    }
                    else
                    {*/
                        break;
                    //}
                }
            }
            if(ok)
            {
                for(int i=0,j=tempnownum+1;i<re1;i++,j++)
                {
                    int nowpos = cc[j];
                    rere1.push_back(pos[nowpos][num[nowpos]-1]);
              //      cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
                    num[nowpos] --;
                    ccin[j] = false;
                }
                ok = false;
                nownum = n-1;
                int ti = 0;
                for(did=1;did<=n;did++)
                {
                    double temp = (double)(x2) / (double)(did);
                    while(nownum>=0&&((!ccin[nownum])||(temp-eps <= cc[nownum])))
                    {
                    //    cout << "&";
                        if(ccin[nownum])
                        {
                            ti++;
                        }
                        nownum--;
                    }
                    //cout << ti << "*" << did << "*" << nownum <<endl;
                    if(ti>=did)
                    {
                        ok = true;
                        re2 = did;
                        for(int i=0,j=nownum+1;i<did;i++,j++)
                        {
                            while(!ccin[j])
                            {
                                j++;
                            }
                            int nowpos = cc[j];
                            rere2.push_back(pos[nowpos][num[nowpos]-1]);
                      //      cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
                            num[nowpos] --;
                            ccin[j] = false;
                        }
                        break;
                    }
                }
            }
            if(ok||rev)
            {
                break;
            }
            else
            {
                rev = true;
                int temp = x2;
                x2 = x1;
                x1 = temp;
            }
        }
        if(ok)
        {
            if(rev)
            {
                cout << "Yes\n" << re2 << " " << re1 << "\n" << rere2[0];
                for(int i=1;i<re2;i++)
                {
                    cout << " " << rere2[i];
                }
                cout << "\n" << rere1[0];
                for(int i=1;i<re1;i++)
                {
                    cout << " " << rere1[i];
                }
                cout << endl;
            }
            else
            {
                cout << "Yes\n" << re1 << " " << re2 << "\n" << rere1[0];
                for(int i=1;i<re1;i++)
                {
                    cout << " " << rere1[i];
                }
                cout << "\n" << rere2[0];
                for(int i=1;i<re2;i++)
                {
                    cout << " " << rere2[i];
                }
                cout << "\n";
            }
        }
        else
        {
            cout << "No\n";
        }
    }
    return 0;
}

/*最小差值a
简化步骤
临界扩大化,随时检查数据范围
双向判断,简化步骤*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值