ABC173-E

E - Multiplication 4

Face


题意

  • 给定一个长度为 n n n的数组 a a a,从中选 k k k个数,使其乘积最大

数据范围: 1 ≤ K ≤ N ≤ 1 0 6 , ∣ A i ∣ ≤ 1 0 9 1\leq K\leq N \leq 10^6, |A_i| \leq 10^9 1KN106,Ai109


前置技能

  • 聪明脑瓜
  • 积化和

Tutorial:

  • 先分情况讨论
    • 输出是正数的情况:
      • 负数两两凑一对儿,加上部分正数 $(neg.size()/2*2) + pos.size() >= k $
      • 当k是奇数, 必须有正数参与进来配平 ( k & 1 ) < = p o s . s i z e ( ) (k \& 1) <= pos.size() (k&1)<=pos.size()
    • 输出是0的情况:有0
    • 输出是负数的情况:
      • 负数排序取前k个?
      • 大❌特❌
      • 有正数进行干扰, 负数同正数类似,不能无脑取前k

  • 众所周知:

a × b × c = d × e × f log ⁡ ( a × b × c ) = log ⁡ ( d × e × f ) log ⁡ ( a ) + log ⁡ ( b ) + log ⁡ ( c ) = log ⁡ ( d ) + log ⁡ ( e ) + log ⁡ ( f ) \begin{aligned} a\times b \times c & = d\times e\times f \\ \log(a\times b \times c)& = \log(d\times e\times f)\\ \log(a) + \log(b)+\log(c) & = \log(d) + \log(e)+\log(f) \end{aligned} a×b×clog(a×b×c)log(a)+log(b)+log(c)=d×e×f=log(d×e×f)=log(d)+log(e)+log(f)

  • 先按绝对值sort, 然后维护log前缀和

复杂度: O ( n l o g ( n ) + k 2 ) O(nlog(n) + \frac{k}{2}) O(nlog(n)+2k)


code:



#include 

using namespace std;
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db long double
#define eps 1e-3
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair
#define pdd pair
#define endl "\n"
const ll mod = 1e9 + 7;
const ll maxn = 2e5 + 10;
deque<ll> a, pos, neg;
db posd[maxn], negd[maxn];

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n, k, zero = 0;
    cin >> n >> k;

    _rep(i, 1, n) {
        ll x;
        cin >> x;
        if (x < 0) {
            neg.push_back(-x);
        } else if (x > 0) {
            pos.push_back(x);
        } else zero++;
    }

    sort(all(pos), greater<ll>());
    sort(all(neg), greater<ll>());

    ll res = 1;
    if ((k & 1) <= pos.size() && (neg.size()/2*2) + pos.size() >= k) {
        // 找正数
        pos.push_front(1);
        neg.push_front(1);

        _for(i, 1, pos.size()) {
            posd[i] = posd[i - 1] + log(pos[i]);
        }
        _for(i, 1, neg.size()) {
            negd[i] = negd[i - 1] + log(neg[i]);
        }
        int ind = 0;
        db ans = 0;
        for (int i = 0; i < neg.size() &&  i <= k; i += 2) {
            if ( k - i < pos.size() && posd[k - i] + negd[i] > ans) {
                ans = posd[k - i] + negd[i];
                ind = i;
            }
        }
        _rep(i, 1, ind) {
            res = (res * neg[i]) % mod;
        }
        _rep(i, 1, k - ind) {
            res = (res * pos[i]) % mod;
        }
        res = res % mod;
    } else if (zero) {
        res = 0;
    } else {
        sort(all(neg), [](ll a,ll b){
            return abs(a)<abs(b);
        });
        sort(all(pos));

        pos.push_front(1);
        neg.push_front(1);
        _for(i,1,pos.size()){
            posd[i] = posd[i-1] + log(pos[i]);
        }
        _for(i, 1, neg.size()){
            negd[i] = negd[i-1] + log(neg[i]);
        }
        db mn = oo;
        int ind = 0;
        for(int i = 1; i<=k && i < neg.size();i+=2){
            if( k-i >= 0 && k-i < pos.size() && mn > posd[k-i] + negd[i]){
                mn = posd[k-i] + negd[i];
                ind = i;
            }
        }
        _rep(i, 1, ind){
            res = res * (-neg[i])%mod;
            res = (res + mod)%mod;
        }
        _rep(i, 1, k-ind){
            res = (res*pos[i]%mod + mod)%mod;
        }


    }
    cout << (res + mod) % mod << endl;
}

你可能感兴趣的:(好题,观察,贪心)