牛客练习赛87 总结

目录​​​​​​​

A-中位数(贪心)

题目链接

题意

思路

代码

B-k小数查询(尺取法)

题目链接

题意

思路

代码

C-牛老板(记忆化搜索+贪心)

题目链接

题意

思路

代码

收获


 

A-中位数(贪心)

题目链接

        A-中位数_牛客练习赛87 (nowcoder.com)

题意

牛客练习赛87 总结_第1张图片  

思路

        其实就是一串数字,删去一个加到另一个上,求中位数,这里的中位数如果总数是偶数的话那么就去中间靠右的,实际上按照题目的式子即可。

        很容易能用贪心得到每一次最优的方案就是让次大的加到最大的上,最大的一直堆,那么经过k次就减少k个数,这里特判一下如果只有一个的话,那么就输出总数。

代码

inline void Case_Test()
{
    cin>>n>>k;
    sum=0;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    sort(a+1,a+1+n);
    if (n-k==1) cout<

B-k小数查询(尺取法)

题目链接

        B-k小数查询_牛客练习赛87 (nowcoder.com)

题意

牛客练习赛87 总结_第2张图片

思路

        我一开始看感觉是单调队列,一个队列维护满足条件的情况,但是我还是太年轻了,这样完全行不通,不能得到所有满足条件的区间个数。

        后面就用尺取法,在博客里之前也遇到一个尺取法。

尺取法,一种神奇的技巧。在Codeforces中显示它的算法名称叫做"two pointers", 直译成中文的话叫双指针法。 顾名思义,像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。

         上次那个题给了我这个题灵感,如果遇到一个满足条件的,求个数,实际上就会有两个指针在这个[l,r]区间上往左往右,那么个数就是(suml+1)\times(sumr+1),那么在这里题里面首先可以找到x所在的pos位置,然后就对每一个a[i]

        这里我一开始是分成左右两个区间,也就是小于pos的满足的,还有大于pos满足的,这里值得反思反思。实际上我可以pos左边的贡献a个小于x的点,pos右边贡献b个小于x的点,所以我们需要每次移动,l++,r++,当不满足条件的时候就不必要进行了,后面更不会满足条件了。

        再处理point数组(也就是存多少个),这个多少个是这么理解的,在pos左边的就看它左边还有多少个满足条件的,如果是在pos右边的那就看它右边有多少个满足条件的,因为我们的suml和sumr就是这样处理的。

        左边是当前a[i]

代码

inline void Case_Test()
{
    cin>>n>>x>>k;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        if (a[i]==x) pos=i;//pos记录x所在位置
    }
    num=0;
    cnt=0;
    for (int i=1;i=p&&l<=p)
    {
        if (r==p)
        {
            cnt=0;
            for (int i=pos+1;i<=n;i++) 
                if (a[i]>x) cnt++;
                else break;
            ans+=(cnt+1)*(point[l]+1);
        }
        else if (l==p)
        {
            cnt=0;
            for (int i=pos-1;i>=1;i--) 
                if (a[i]>x) cnt++;
                else break;
            ans+=(cnt+1)*(point[r]+1);
        }
        //因为point[p]这个pos处的特殊点没有处理,所以在这里暴力一下
        else
        {
            ans+=(point[l]+1)*(point[r]+1);
        }
        l++;r++;
        //移动区间
    }
    cout<

C-牛老板(记忆化搜索+贪心)

题目链接

        C-牛老板_牛客练习赛87 (nowcoder.com)

题意

牛客练习赛87 总结_第3张图片

思路

        这个题是后面补的,我也想过记忆化搜索,但是没想到这个贪心的,我想到的是6出一点,但不是最多,然后9出一点,也不是最多,这样加起来正好是n。但是仔细一想,还是得贪心找当前最大的6的次方,或者当前最大的9的次方,然后去取min,这样贪心是最优的,假如有一个6^a不选,去选一个6^{a-1},那么剩下了5个6^{a-1};同理,9^b也不选,去选9^{b-1},也空出了8个9^{b-1},那么这两个空出来的不是一个系数能够解决的,所以还得是取最大的。 

         然后就是用map用记忆化搜索了。

代码

unordered_mapmp;
inline void init()
{
    for (int i=1;i<=N;i*=6)
        m6[++cnt1]=i;
    m6[++cnt1]=inf;
    for (int i=1;i<=N;i*=9)
        m9[++cnt2]=i;
}
inline int dfs(int n)
{
    if (n<6) return n;
    if (mp[n]) return mp[n];
    int t1=upper_bound(m6+1,m6+1+cnt1,n)-m6;
    int t2=upper_bound(m9+1,m9+1+cnt2,n)-m9;
    return mp[n]=min(dfs(n-m6[t1-1]),dfs(n-m9[t2-1]))+1;
}
inline void Case_Test()
{
    cin>>x;
    cout<

收获

        C题中用unordered_mapmp 108ms

        用mapmp 272ms

你可能感兴趣的:(比赛总结)