奖品分配-头条2019笔试题

奖品分配-头条2019笔试题

有n个人参加编程比赛,比赛结束后每个人都得到一个分数;现在所有人排成一圈(第一个和第n个相邻)领取奖品,要求:

1、如果某个人的分数比左右的人高,那么奖品数量也要比左右的人多;

2、每个人至少得到一个奖品;

问最少应该准备多少个奖品。

输入格式

第一行是整数T,表示测试样例个数。

每个测试样例的第一行是一个整数n,表示参加比赛的人数。

第二行是n个正整数a[i],表示从第1个人到第n个人的分数。

输出格式

对每个测试样例,输出应该准备的最少奖品,每个结果占一行。

数据范围

1≤T≤10,
0<n<\(10^5\),
0<a[i]<\(10^5\)

输入样例:

2
2
1 2
4
1 2 3 3

输出样例:

3
8

java 下标排序

//下标排序
int[] a = new int[n];
Integer[] idx = new Integer[n];
Arrays.sort(idx, (o1, o2)->a[o1]-a[o2]);

奖品分配问题

方法一、\(O(nlog_2^n)\)

我们希望当计算第i个小朋友糖果数量时,它左右分数比他低的小朋友糖果数量已经计算出来了,得分相同或大于没有要求。
因此,我们根据得分排序,得分少的先计算糖果数量。
如果左右未分配,则分配1
如果存在分配的,则分配该小朋友左右分配值中最大值+1

时间复杂度分析,计算次数为:

\[Tnlog_2^n = 10 \times 10^5log_2^{10^5} \approx 1.7\times10^7 \]

实测java超时, 可能排序常数项较大。

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        while(T-- > 0) {
            int n = sc.nextInt();
            int[] a = new int[n];
            
            Integer[] idx = new Integer[n];
            int[] nums = new int[n];
            for(int i=0; i < n; i++) {
                a[i] = sc.nextInt();
                idx[i] = i;
            }
            Arrays.sort(idx, (o1, o2)->a[o1]-a[o2]);
            for(int i=0; i < n; i++) {
                int k = idx[i];
                int left = (k-1+n)% n, right = (k+1)%n;
                int maxn = 0;
                if(a[left] < a[k]) maxn = Math.max(nums[left], maxn);
                if(a[right] < a[k]) maxn = Math.max(maxn, nums[right]);
                nums[k] = maxn + 1;
                //System.out.println("+++"+nums[k]);
            }
            long res = 0L;
            for(int i=0; i < n; i++)
                res = res + nums[i];
            System.out.println(res);
        }
    }
}

方法二、记忆化搜索\(O(n)\)

import java.util.*;
public class Main {
    static int[] f, a;
    static int n;
    static int dfs(int x) {
        if(f[x] != 0) return f[x];
        if(a[(x+n-1) % n] >= a[x] && a[(x+1) % n] >= a[x] ) 
            return f[x] = 1;
        int v = 0;
        if(a[(x+n-1)% n] < a[x]) 
            v = dfs((x+n-1)% n);
        if(a[(x+1)% n] < a[x]) 
            v = Math.max(v, dfs((x+1)%n));
        return f[x] = v + 1;
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int T = sc.nextInt();
        while(T-- > 0) {
            n = sc.nextInt();
            a = new int[n];
            f = new int[n];
            for(int i=0; i < n; i++)
                a[i] = sc.nextInt();
            for(int i=0; i < n; i++)
                dfs(i);
            long res = 0L;
            for(int i=0; i < n; i++)
                res = res + f[i];
            System.out.println(res);
        }
    }
}
上一篇:【JAVA习题三】求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字。例如2+22+222+2222+22222(此时共有5个数相加


下一篇:判断两个数的最大公约数算法JAVA代码