省赛训练题(HDU4968,HDU4970,HDU4864)

11 篇文章 0 订阅
3 篇文章 0 订阅

省赛训练,关键还是心态问题,心态放平,才能有高效发挥。

 

这一套题整体感觉质量还是挺好的,各种考验思维的题目,确实很有收获。

 

按顺序码了前三题,那就让我们来分析一下

 

 

A.Improving the GPA

 

 

思路:拿到题目后,第一思路就是贪心,压分数的上下值肯定就能得到最值结果。不过,两头的特殊数据就成了比较棘手的问题,考虑分数两边扩展不会影响结果,而扩展到最边上时由于端点的特殊性就可以得到最优值。

于是极限存放60和100,之后贪心其余的步骤。对于贪心的过程,由单步贪心进化到时时贪心。然后对于均分过高或过低的情况单独考虑。

不过对于60和100的数量问题上确实出了不少的问题,最终还是考虑不周而最终报废。

后来经研究发现,既然贪心就完全可以贪心得彻底一点,先将所有数据都处理成60(或100),经以上分析这两个值越多越好。然后对于多余(或不足)的数据,开始依次补进(或消去),直至85(或69),因为进一步的处理不会对分产生任何影响,因此将85(或69)作为为换点标志。

最后就是需要注意,均分过高或过低的情况,由于这种情况下,除最后一个数据外所有值都被设为85(或69),所以最后的结果一定过高(或过低),不过并不影响最终结果,直接按最值100(或60)处理即可。

由此可见,确实贪心过程需要明确的思路和冷静的大脑,不需要将过程复杂化,尽量找出较为普适的同一方程。

最后附上AC代码以及悲催狂WA代码(变量以w开头,位于注释部分),而两个程序结果(***开头为被WA的程序数据)差异经命令行比较(fc)结果如下图。

 

 

/*
Author:Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

double getscore(int x)
{
    if(x<=69&&x>=60)
    {
        return 2.0;
    }
    else if(x<=74&&x>=70)
    {
        return 2.5;
    }
    else if(x<=79&&x>=75)
    {
        return 3.0;
    }
    else if(x<=84&&x>=80)
    {
        return 3.5;
    }
    else if(x<=100&&x>=85)
    {
        return 4.0;
    }

    return false;
}

int main()
{
    int n,t,score;
    while(scanf("%d",&t)!=EOF)
    {
        /*double wscore[110];
        for(int i=60;i<=69;i++)
        {
            wscore[i] = 2.0;
        }
        for(int i=70;i<=74;i++)
        {
            wscore[i] = 2.5;
        }
        for(int i=75;i<=79;i++)
        {
            wscore[i] = 3.0;
        }
        for(int i=80;i<=84;i++)
        {
            wscore[i] = 3.5;
        }
        for(int i=85;i<=100;i++)
        {
            wscore[i] = 4.0;
        }*/
        while(t--)
        {
            scanf("%d%d",&score,&n);
            double maxscore,minscore;
            int totalscore = score * n;
            int lastmaxscore = totalscore - 60 * n;
            maxscore = 2.0 * (double)(n);
            int maxid = n;
            while(lastmaxscore)
            {
                if(lastmaxscore > 25 && maxid > 1)
                {
                    lastmaxscore -= 25;
                    maxscore += 2.0;
                }
                else
                {
                    if(lastmaxscore > 40)
                    {
                        maxscore += 2.0;
                    }
                    else
                    {
                        maxscore = maxscore + getscore(lastmaxscore + 60) - 2.0;
                    }
                    lastmaxscore = 0;
                }
                maxid--;
            }
            maxscore /= (double)(n);
            int lastminscore = 100 * n - totalscore;
            minscore = 4.0 * (double)(n);
            int minid = n;
            while(lastminscore)
            {
                if(lastminscore > 31 && minid > 1)
                {
                    lastminscore -= 31;
                    minscore -= 2.0;
                }
                else
                {
                    if(lastminscore > 40)
                    {
                        minscore -= 2.0;
                    }
                    else
                    {
                        minscore = minscore + getscore(100 - lastminscore) - 4.0;
                    }
                    lastminscore = 0;
                }
                minid --;
            }
            minscore /= (double)(n);
            printf("%.4f %.4f\n",minscore,maxscore);
            /*
            int wn;
            double k;
            k = (double)(score);
            wn = n;
            //max
            double wmaxsum = k*(double)(wn);
            int wnmax = wn;
            int wm60 = (int)(((89.0-k)*(double)(wn))/29.0);
            double wmaxs = (double)(wm60)*2.0;
            if(k>=85)
            {
                wmaxs = 4.0;
            }
            else
            {

                wmaxsum -= (double)(wm60)*60.0;
                wnmax -= wm60;
                //int wmaxave = (int)(wmaxsum / (double)(wnmax));
                //int wmaxmod = (wmaxave % 5);
                //int wmaxan = wmaxave - wmaxmod;
                //wmaxs += wscore[wmaxan]*(double)(wnmax-1);
                //int maxone = wmaxsum - (double)(wmaxan) * (double)(wnmax - 1);
                //wmaxs += wscore[maxone];
                //wmaxs /= double(wn);
                //wmaxsum -= (double)(wm60)*60.0;
                //wnmax -= wm60;
                while(wnmax>1)
                {
                    int wmaxave = (int)(wmaxsum / (double)(wnmax));
                    int wmaxmod = wmaxave % 5;
                    int wmaxan = wmaxave - wmaxmod;
                    wmaxs += wscore[wmaxan];
                    wmaxsum -= (double)(wmaxan);
                    wnmax--;
                }
                wmaxs += wscore[(int)(wmaxsum)];
                wmaxs /= (double)(wn);
            }
            //min
            double wminsum = k*(double)(wn);
            int wnmin = wn;
            int wm100 = (int)(((k-65.0)*(double)(wn))/35.0);
            double wmins = (double)(wm100)*4.0;
            if(k<=69)
            {
                wmins = 2.0;
            }
            else
            {
                wminsum -= (double)(wm100)*100.0;
                wnmin -= wm100;
                while(wnmin>1)
                {
                    int wminave = (int)(wminsum / (double)(wnmin));
                    int wminmod = 4 - (wminave % 5);
                    int wminan = wminave + wminmod;
                    wmins += wscore[wminan];
                    wminsum -= (double)(wminan);
                    wnmin--;
                }
                wmins += wscore[(int)(wminsum)];
                wmins /= (double)(wn);
                //int wminave = (int)(wminsum / (double)(wnmin));
                //int wminmod = 4 - (wminave % 5);
                //int wminan = wminave + wminmod;
                //wmins += wscore[wminan]*(double)(wnmin-1);
                //int minone = wminsum - (double)(wminan) * (double)(wnmin - 1);
                //wmins += wscore[minone];
                //wmins /= double(wn);
            }
            printf("*****%.4f %.4f\n",wmins,wmaxs);
           */
        }
    }
    return 0;
}

 

 

 

 

 

 


B.Killing Monsters

 

 

思路:塔防打怪兽问题,题目很清晰,就是区间线段型数据覆盖处理问题。一开始考虑到用树状数组可以降低求和的时间,然而却发现求和之前,将区间数据分配到对应点上就是个很麻烦的问题。而且,对于测试数据较多的情况,完全可以处理全部点,然后作为静态数据来处理,这就免去了反复运算维护的麻烦,将求和过程变成了独立的操作。

那么,现在最大的问题就是如何处理这些数据数据。

或许,这就有点数学导数的思维了,或者可以说信号里面冲激与阶跃的思想。将区间端点作为突变点来处理,存入第一个attack数组,第二个数组hurt对第一个attack数组进行累加,由突变向总值转变,得到每点的对应伤害值,最后引入第三个blood数组,从后往前累加求和,计算出后项累加和。三个数组的计算是三个相互独立的过程,因此相当巧妙地将时间复杂度降到了线性的O(n),完美解决。

当然,这种思维对于以后处理区间线段数据也会有很好的启示作用。

 

 

/*
Author:Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

long long attack[maxn];
long long hurt[maxn];
long long blood[maxn];

int main()
{
    int n,m,k;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)
        {
            break;
        }
        memset(attack,0,sizeof(attack));
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            int l,r,d;
            scanf("%d%d%d",&l,&r,&d);
            attack[l] += d;
            attack[r+1] -= d;
        }
        long long temphurt = 0;
        for(int i=1;i<=n;i++)
        {
            temphurt += attack[i];
            hurt[i] = temphurt;
        }
        blood[n] = hurt[n];
        for(int i=n-1;i>=1;i--)
        {
            blood[i] = blood[i+1] + hurt[i];
        }
        scanf("%d",&k);
        int sum = 0;
        for(int i=0;i<k;i++)
        {
            long long h;
            int x;
            scanf("%lld%d",&h,&x);
            if(h>blood[x])
            {
                sum++;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

 

 

 

 

 

C.Task

 

 

思路:求解最优值,又是一道典型的贪心问题,乍一看有点类似于线性规划。如果只有一维因素,那肯定将最重要的任务分配给最强力的机器。

然而,当问题引入二元时,就不那么简单了,如果仅仅简单的区分两个变量的重要性来排序,当一维变量来排序,就会可能忽略一种很普遍的极端情况(高效高能机器处理中效低能任务,中效中能机器却无法处理低效高能任务)。

所以,开始考虑分别贪心的思路。

首先,当然还是按主次因素将任务和机器从大到小排序。

对于任务和机器两个对象,由于最终要计算与任务相关的金额,所以考虑将任务作为遍历对象。

如果分别遍历的话,O(n^2)的时间复杂的确实难以接受,于是开始考虑优化方法。

于是想到每次将满足第一变量时间效率的机器单独提出处理,这样所有机器都只会被处理一遍,时间复杂度被降为O(n+n)。

而对于被提取出的机器,找出满足要求的第二变量机器功能最小的机器,由于第一变量肯定满足无需再考虑,这样就可以给别的任务留出更高能的机器。然而很尴尬的问题是,就这么个找第二变量最小的满足功能的机器,也可能会成为一个长达O(n)的过程,而最坏情况又一次被降到了无法接受的O(n^2)。

仔细分析,发现,对于被提取出的机器,它的第一变量已经没有任何存在需要了(肯定满足),而两个变量之间的对应关系也就不那么重要了。分析输入数据可以发现,第二变量的取值范围只有100,那么就完全可以将所得机器的第二变量单独处理到一个大小仅为100的level数组中,通过数组计数来实现机器第二变量与任务的匹配,成功将时间复杂的降为O(n*100),完美AC

最后就是数组遍历的过程中细心点,谨防数组越界就好了

 

 

/*
Author:Owen_Q
*/

#include <bits/stdc++.h>

using namespace std;

typedef struct PRO
{
    int x;
    int y;
}Pro;

bool cmp(const Pro &x1,const Pro &x2)
{
    if(x1.x>x2.x)
    {
        return true;
    }
    else if(x1.x==x2.x)
    {
        if(x1.y>x2.y)
        {
            return true;
        }
    }
    return false;
}

const int maxn = 1e5+10;

Pro task[maxn];
Pro machine[maxn];

int level[105];

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(level,0,sizeof(level));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&machine[i].x,&machine[i].y);
        }
        sort(machine,machine+n,cmp);
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&task[i].x,&task[i].y);
        }
        sort(task,task+m,cmp);
        int sum = 0;
        long long money = 0;
        for(int i=0,j=0;j<m;j++)
        {
            while(machine[i].x>=task[j].x&&i<n)
            {
                level[machine[i].y]++;
                i++;
            }
            for(int k=task[j].y;k<=100;k++)
            {
                if(level[k]>0)
                {
                    level[k]--;
                    sum++;
                    money += 500 * task[j].x + 2 * task[j].y;
                    break;
                }
            }
        }
        printf("%d %lld\n",sum,money);
    }
    return 0;
}

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值