ABC.173.E - Multiplication 4

ABC.173.E - Multiplication 4

传送门

题意:求最大子序列乘积。

思路:贪心,先对数组排序,讨论 k k k的奇偶性,再两个两个地取。因为两个负数和两个正数的乘积都是正数。

1. k 1.k 1.k是奇数,我们先去最大的数作为初始答案,然后特判一下最大数是否为负数,

如果最大的数都为负数,且 k k k是奇数,显然答案只能为负,这时我们取较小的正数是最优的,若初始答案为正数,我们就贪心取分别设置两个指针,从左边和右边,贪心地取,谁大取谁即可。

2. k k k是偶数同理,直接开始从左边和右边贪心地取,这样肯定保证取 k k k个。

此处贪心是可以把0的情况计算的。

e p : − 1 , 0 , 2 , 3 , 5 ep:-1,0,2,3,5 ep:1,0,2,3,5。 因为我们排序后负数始终在 0 0 0后面。

所以 − 1 × 0 < 2 × 3 -1\times 0< 2\times 3 1×0<2×3。 也满足情况。

特殊情况2: − 1 , 1 , 2 , 3 。 k = 3 -1,1,2,3。k=3 1,1,2,3k=3也是满足的,因为 − 1 × 1 < 1 × 2 -1\times 1<1\times 2 1×1<1×2

需要注意的时乘的时候要取模,避免爆 l o n g   l o n g long\ long long long

时间复杂度 : O ( n l o g n ) O(nlogn) O(nlogn)

#include
using namespace std;
typedef long long ll;
const int N=2e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
ll a[N];
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%lld",&a[i]);
	sort(a,a+n);
	int l=0,r=n-1,w=1; 
	ll ans=1;
	if(k&1) ans=a[r--],k--,w=(ans<0?-1:1);
	while(k){
		ll x=a[l]*a[l+1],y=a[r]*a[r-1];
		if(x*w>y*w) ans=(ans*(x%mod))%mod,l+=2;
		else ans=(ans*(y%mod))%mod,r-=2;
		k-=2;
	}
	printf("%lld\n",(ans%mod+mod)%mod);
	return 0;
}

你可能感兴趣的:(Atcoder题解,贪心)