Codeforces Round #517 C.Cram Time

这道题当初还以为是什么高深莫测的算法,dp还是搜索剪枝,没想到居然是道普普通通的贪心+模拟。这都没看出来,服了。

这道题错在两个地方:

  • 数学推导有问题。我推导到了n(n+1)/2<=(a+b),但是接下来犯错了。我没有继续推导n最大时的不等式,而是想当然的计算了floor(sqrt(2*(a+b))),因为我觉得n和n+1不就相差1嘛,稍微大一点,开根号舍去小数位数不就完了嘛。但是还真不是这样的。当n最大时,设为N,我们只有不等式推导的N<=sqrt(2(a+b))<=N+1,而不能确定开方得数到底和N差几,可能差小于1,那向下取整对,也可能差大于1,那向下取整就错(如10亿)。这时候,就要加个循环,不断向下减一即可。

以后一定记住,求n(n+1)<x的最大整数n,向下取整后,还要有一步循环相减,不管这一步是否有效

  • 算法设计有问题。讲真,虽然上面的式子我很早就推出来了,但是我一直不知道该拿什么策略填。没想到正解的策略这么的简单,简单到弱智。。。还是脑子不灵光啊。其实因为我没有意识到,既然可以确定能够填充的最长耗时学案编号k,那就可以确定,所有的从耗时1~k的所有学案,一定都可以填到这两天里,只是如何填的策略问题。正确策略是,从学案耗时k开始填,k,k-1,k-2,...2,1,每一个都填到两天中能填进去的那天,就这么简单。。。
#include <bits/stdc++.h>
using namespace std;
vector<int> va,vb;
int main()  {
    int a,b;
    cin>>a>>b;
    int n=sqrt(2.0*(a+b));
    while (n*(n+1)/2>(a+b))    n--;
    //cout<<"n=\t"<<n<<endl;
    for (int i=n;i>=1;i--)  {
        if (a>=i)   {a-=i;va.push_back(i);}
        else    vb.push_back(i);
    }
    cout<<va.size()<<endl;
    if (!va.empty())    cout<<va[0];
    for (int i=1;i<(int)va.size();i++)
        cout<<' '<<va[i];
    cout<<endl;
    cout<<vb.size()<<endl;
    if (!vb.empty())    cout<<vb[0];
    for (int i=1;i<(int)vb.size();i++)
        cout<<' '<<vb[i];
    cout<<endl;
    return 0;
}

posted @ 2018-10-22 08:54  CF过2100就买ARCTERYX  阅读(183)  评论(0编辑  收藏  举报