【2020.11.28提高组模拟】T2 序列(array)

序列(array)

题目描述

​给定一个长为 (m) 的序列 (a)
有一个长为 (m) 的序列 (b),需满足 (0leq b_i leq n)(sum_{i=1}^m a_ib_i leq D)(b_i) 为整数。
​求 (sum b_i + k min_{i=1}^m{b_i}) 的最大值。

输入格式

​第一行一个正整数 (T),表示数据组数。
​对于每组数据,第 (1) 行四个整数 (n, m, k, D)
​第 (2)(m) 个整数 (a_i)

输出格式

​对于每组数据,第一行一个整数 (ans)

数据范围

​对于 (15\%) 的数据,(n, m leq 100)
​对于 (30\%) 的数据,(n leq 10^6)(m leq 100)
​对于另 (30\%) 的数据,(T = 1) 且数据随机。
​对于 (100\%) 的数据,(1 leq n leq 10^9)(1leq k, m leq 2 imes 10^5)(1 leq D leq 10^{18})(1leq a_i leq 5000)

时空限制

​时间限制:2s
​空间限制:256MB

题解

首先贪心策略,若(a_i le a_j),则(b_i ge b_j)。把(a)排序,枚举(b)中有多少个是(n)。若到(n)的有(s),设(b_{s+1}=x),则答案为$$s*n+x+lfloordfrac{D-nsums_{i=1}a_i-a_{s+1}*x}{sumn_{i=s+2}a_i} floor$$
去掉(s*n),是形如(x+alfloordfrac{bx+c}{d} floor)的,这个函数形如锯齿
三种情况会达到最大值

  1. 第一个峰
    在这里插入图片描述

  2. 最后一个峰
    在这里插入图片描述

  3. 结束点
    在这里插入图片描述

对应到题目上就是
1.尽可能提高(minb),剩余去提高(b_s)
2.尽可能提高(b_s),剩余去提高(minb)
3.(minb+1),剩下全部提高(b_s)

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll t,n,m,k,d,ans,x,ans1,ans2,ans3,minb,a[200001],sum[200001];
ll calc(int i,int minb) {return n*(i-1)+min((x-minb*(sum[m]-sum[i]))/a[i],n)+minb*(k+m-i); }
int main()
{
	freopen("array.in","r",stdin);
	freopen("array.out","w",stdout);
	scanf("%lld",&t);
	while (t--)
	{
		scanf("%lld%lld%lld%lld",&n,&m,&k,&d);
		ans=0;
		for (int i=1;i<=m;++i)
			scanf("%lld",&a[i]);
		sort(a+1,a+m+1);
		for (int i=1;i<=m;++i)
			sum[i]=sum[i-1]+a[i];
		for (int i=1;i<=m;++i) //a[1]~a[i-1]=n
		{
			x=d-n*sum[i-1];
			if (x<0) break;
			minb=(x-a[i]*(n+1))/(sum[m]-sum[i])+1;//a[i]~a[n]>=minb
			ans1=x/(sum[m]-sum[i-1]);//方案1,使b[s]和b[s-1]~b[m]一样
			if (ans1<0) ans1=0;
			if (ans1>n) ans1=n;
			ans=max(ans,calc(i,ans1));
			ans2=min(ans1,(x-min((x-minb*(sum[m]-sum[i]))/a[i],n))/(sum[m]-sum[i]));//b[s]取最大
			if (ans2<0) ans2=0;
			if (ans2>n) ans2=n;
			ans=max(ans,calc(i,ans2));
			ans3=min(ans1,minb);//minb在前面已经先加了1
			if (ans3<0) ans3=0;
			if (ans3>n) ans3=n;
			ans=max(ans,calc(i,ans3));
			//ans1,ans2,ans3都代表着b[s-1]~b[m]
		}
		printf("%lld
",ans);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;	
}
原文地址:https://www.cnblogs.com/Livingston/p/14057611.html