2020牛客暑期多校训练营(第八场)K-Kabaleo Lite

题目传送门:2020牛客暑期多校训练营(第八场)K-Kabaleo Lite

题目大意:

有n种菜,给出两组长度为n的数组,第一组表示每种菜的利润(可能为负),第二组表示每种菜的份数,每次给一个顾客上菜,必须是从第一份开始的连续的菜,问最多可以有给几个顾客上菜(优先保证),最大利润是多少。 
 

题目思路:

这道题目的思路有两个版本,一个想法是比赛时候的想法,还有一个想法是看了别人代码的想法,不管哪种想法都有一个不可忽视的重点,高精度问题,这道题目的答案和所求的前缀和数组,都是会爆long long,__int128是最合适的方法,unsigned long long属于无符号整型需要特殊处理负数的情况,大数模板代码量会相对增加。

__int128输入输出模板传送门:__int128

思路1(比赛思路,复杂)

首先求出利润的前缀和,份数只记录min(当前,上一个),对前缀和降序排序,排序时需要记录原始下标排序,遍历前缀和,记录一个右边界,如果当前前缀和的原始下标在右边界的左边,ans累加利润乘份数,更新当前已经用过的份数即可。

ac代码如下:

#include
using namespace std;
#define ll long long
#define ull unsigned long long
 
const int maxn = 1e5+5;
struct node{
    ll val;
	__int128 sum;
    int i;
}a[maxn];
ll b[maxn];
 
bool cmp(node x,node y)
{
    return x.sum>y.sum;
}
 
inline void print(__int128 x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}
 
int main()
{
    int t,cas=0;
    scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i].val);
            a[i].sum=a[i].val+a[i-1].sum;
            a[i].i=i;
        }
        for(int i=1;i<=n;i++){
            scanf("%lld",&b[i]);
            if(i!=1) b[i]=min(b[i],b[i-1]);
        }
        sort(a+1,a+1+n,cmp);
        int x=n;
        ll cnt=0;//记录已经消耗的数量 
        __int128 ans=0;
        for(int i=1;i<=n;i++){
            if(x>=a[i].i) ans+=a[i].sum*(b[a[i].i]-cnt),cnt=b[a[i].i],x=a[i].i;
        }
        printf("Case #%d: %lld ",++cas,b[1]);
        print(ans);
        puts("");
    }
    return 0;
 }

思路2(补题思路,简单)

同样首先求出利润的前缀和,份数只记录min(当前,上一个),无需排序,遍历份数数组,同时更新一个利润数组的最大值,当份数变少的时候,那么份数多的这部分就在之前的最大利润乘份数差值即可,注意遍历结束需要把最小份数单独计算一次。

ac代码如下:

#include
using namespace std;
#define ll long long

inline void print(__int128 x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}

const int maxn = 1e5+5;
ll a[maxn],b[maxn];
__int128 s[maxn];

int main()
{
	int t,cas=0;
	scanf("%d",&t);
	while(t--){
		int n;scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
			s[i]=s[i-1]+a[i];
		}
		for(int i=1;i<=n;i++){
			scanf("%lld",&b[i]);
			if(i!=1) b[i]=min(b[i],b[i-1]); 
		}
		__int128 ans=0,maxx=s[1];
		for(int i=2;i<=n;i++){
			if(b[i]

 

你可能感兴趣的:(训练赛题目解题报告)