JZOJ7月17日提高组T2 数组

题目

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

输入样例1:
3 2 7
5 4 2
输入样例2:
5 3 1
5 4 3 5 5

Sample Output

输出样例1:
999999732
输出样例2:
0

Data Constraint

在这里插入图片描述

题解

题意

给定一个序列,可以选择一些元素进行最多 k k 次操作,每次操作可以对序列内一个元素增加或减少给定的数 x x ,问这个序列的最小乘积是多少,对 1 0 9 + 7 10^9+7 取模

分析

既然要乘积最小,那么尽量使乘积为负数
那么就要使序列内负数的个数有奇数个
如果当前序列内负数个数为偶数个,有两种方法:
1、将一个负数增加至非负数
2、将一个非负数减少至负数
可以取负数和非负数里绝对值最小的两个数,判断是减还是加
如果序列负数为奇数时(包括上述更改后)
把所有数全部变成绝对值
然后将最小的数加上 x x
为什么是最小的数呢?
设未更改前序列乘积为 S S ,要把当前值为 a [ i ] a[i] 的数加上 x x ,那么更改后的乘积就为 S a [ i ] ( a [ i ] + x ) = S a [ i ] a [ i ] + S a [ i ] x = S + S a [ i ] x \dfrac{S}{a[i]}*(a[i]+x)=\dfrac{S}{a[i]}*a[i]+\dfrac{S}{a[i]}*x=S+\dfrac{S}{a[i]}*x
显而易见, a [ i ] a[i] 越小式子总值越大
那么就可以用堆来维护最小值
最后输出时判一下正负(或许不用)

Code

#include<cstdio>
#include<cmath>
#define mod 1000000007
using namespace std;
int n,m,v,i,nmax,pmin,nnum,pnum,f,num,a[200005];
long long d[400005],ans;
bool b;
void up(int x)
{
	long long t;
	while (x>1&&d[x/2]>d[x])
	{
		t=d[x/2];
		d[x/2]=d[x];
		d[x]=t;
		x/=2;
	}
}
void down(int x)
{
	int y;
	long long t;
	while ((x*2<=num&&d[x]>d[x*2])||(x*2+1<=num+1&&d[x]>=d[x*2+1]))
	{
		y=x*2;
		if (y+1<=num&&d[y+1]<d[y]) y++;
		t=d[x];
		d[x]=d[y];
		d[y]=t;
		x=y;
	}
}
int main()
{
	nmax=-1234567890;
	pmin=1234567890;
	scanf("%d%d%d",&n,&m,&v);
	for (i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if (a[i]<0) f++;
		if (a[i]<0&&a[i]>nmax) 
		{
			nmax=a[i];
			nnum=i;
		}
		if (a[i]>=0&&a[i]<pmin)
		{
			pmin=a[i];
			pnum=i;
		}
	}
	if (f%2==0)
	{
		if (abs(nmax)>pmin)
		{
			while (a[pnum]>0&&m>0)
			{
				m--;
				a[pnum]-=v;
			}
			if (a[pnum]<0) b=true;
		}
		else
		{
			while (a[nnum]<0&&m>0)
			{
				m--;
				a[nnum]+=v;
			}
			if (a[nnum]>0) b=true;
		}
	}
	else b=true;
	ans=1;
	if (m>0)
	{
		for (i=1;i<=n;i++)
		{
			a[i]=abs(a[i]);
			num++;
			d[num]=a[i];
			up(num);
		}
		while (m--)
		{
			d[1]+=v;
			down(1);	
		}
		for (i=1;i<=n;i++)
			ans=ans*(d[i]%mod)%mod;
		printf("%d\n",(mod-ans)%mod);
	}
	else
	{
		for (i=1;i<=n;i++)
			ans=ans*(abs(a[i])%mod)%mod;
		if (b==true) printf("%d\n",(mod-ans)%mod);
		else printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/LZX_lzx/article/details/107418700