思路:第九届蓝桥杯最后一道题,对于从N个中取K个最大,我们可以对k进行考虑
1:k如果是偶数,那么我们可以先进行排序,按理说我们应该从最大数开始取,可是两个负数相乘也有可能最大,于是我们判断最大的两个正数和最小的两个数(可能为负)选取最大的,之后往前挪或者往后挪,直到取完k个数
2:如果k为奇数,情况就比较多了,我们先看最大的数是不是正数,如果是正数,那么它一定会被取到的,因为要保证乘积最大且剩下k-1是偶数,我们就采用1的偶数取法去取,如果最大数为0或负数那我们就一个一个取就行了从最大取到最小保证k个数即可。
3:特殊情况有可能我们取得k个数中其中一定有0,直接特判0
不过代码只AC了12/17个数据,不知道有没有更好的方法,动规不会=.=。
不知道哪里出错了,大佬帮忙看看.
-------------------------------------------更新----------------------------------------------2020-4-25
找到不能ac的原因了:
ans=((a[r]*a[r-1])%mod*ans%mod);
ans=((a[l]*a[l+1])%mod*ans%mod);
以上写才能ac其他方式写都会超ll
原因:
ans=(ans*a[r]*a[r-1])%mod;
ans=(ans*a[l]*a[l+1])%mod;
分析:a[r]*a[r-1]最大10^10在乘以ans会超ll
所以把以下不能ac的代码改成最上边两行写才行。
留着错误代码给大家一个警示作用。
C++ 代码
# include<iostream>
# include<cstdio>
# include<algorithm>
using namespace std;
typedef long long ll;
ll a[100001];
int mod=1000000009;
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)==2)
{
int sum=0;
for(int i=0;i<n;i++)
{
//scanf("%d",&a[i]);
cin>>a[i];
if(a[i]==0)
sum++;
}
sort(a,a+n);
// for(int i=0;i<n;i++)
// printf("%d ",a[i]);
ll ans=1;
int r=0,l=0;
if(k<sum)//t特殊情况,选取的k个数中一定有0,结果一定是0
printf("0\n");
else
{
if(k%2==0)//取偶数个
{
l=0,r=n-1;
while(k>0)
{
if(a[r]*a[r-1]>a[l]*a[l+1])
{
ans=(ans*a[r]*a[r-1])%mod;
r-=2;
k-=2;
}
else
{
ans=(ans*a[l]*a[l+1])%mod;
l+=2;
k-=2;
}
}
}
else//取奇数个
{
k-=1;
r=n-2,l=0;
if(a[n-1]>0)//最大数为正数
{
ans*=a[n-1];
while(k>0)//去偶数个
{
if(a[r]*a[r-1]>a[l]*a[l+1])
{
ans=(ans*a[r]*a[r-1])%mod;
// printf("%lld %lld ",a[r],a[r-1]);
r-=2;
k-=2;
}
else
{
ans=(ans*a[l]*a[l+1])%mod;
// printf("%lld %lld ",a[l],a[l+1]);
l+=2;
k-=2;
}
}
}
else//最大数为0或者负数
{
r=n-2;
ans*=a[n-1];
while(k>0)
{
ans=(ans*a[r])%mod;
r--;
k--;
}
}
}
}
printf("%lld\n",ans);
}
return 0;
}