题意:给出一堆元素,求一个子集,使子集的乘积最大,如有多个,应该使子集元素个数尽量小。
题解:贪心,如果有大于1的正数,那么是一定要选的,注意负数也可能凑出大于1的正数,那么将绝对值大于1的负数两两配对,
如果还剩下一个绝对值大于1的负数,那么在判断一下,那个负数和比它大的最小负数的乘积是否大于1,如果是那么就选这两个。
把所有可能凑成大于1的数选完以后,剩下的数一定比1小,那么就不选。
如果无法凑出大于1的数,那么再分类讨论一下。
挺容易写错。。。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e4+6; struct Num { int a[maxn]; int id[maxn]; int r[maxn]; int sz; Num(){sz = 0;} void push(double x,int i){ a[sz] = x*100; r[sz] = sz; id[sz] = i; sz++; } int _upper_bound(int L,int R,int v) { while(L<R){ int m = (L+R)>>1; if(a[r[m]]>v) R = m; else L = m+1; } return L; } int _lower_bound(int L,int R,int v) { while(L<R){ int m = (L+R)>>1; if(a[r[m]]>=v) R = m; else L = m+1; } return L; } // int id(int x) { return r[x]; } int operator [](int x){ return a[r[x]]; } }P,M; int ans[maxn]; #define GetBound(l,r,v,which) l = which._lower_bound(0,which.sz,v); r = which._upper_bound(0,which.sz,v); #define Add(which,x) ans[sz++] = which.id[which.r[x]]; bool cmp(int x,int y) { return P.a[x] < P.a[y]; } bool cmp2(int x,int y) { return M.a[x] < M.a[y]; } int main() { //freopen("in.txt","r",stdin); int n; scanf("%d",&n); bool zero = false; int pzero; for(int i = 1; i <= n; i++){ double t; scanf("%lf",&t); if(t>0){ P.push(t,i); }else if(t<0){ M.push(-t,i); }else if(!zero) { zero = true; pzero = i; } } sort(P.r,P.r+P.sz,cmp); sort(M.r,M.r+M.sz,cmp2); int m1l,m1r,p1l,p1r; GetBound(m1l,m1r,100,M) GetBound(p1l,p1r,100,P) int sz = 0; int t; for(t = p1r; t < P.sz; t++) Add(P,t) int odd = (M.sz - m1r)&1; for(t = m1r+odd; t < M.sz; t++) Add(M,t) if(odd){ if(m1r>0 && M[m1r]/10000.*M[m1r-1] > 1 ) { Add(M,m1r) Add(M,m1r-1) } } if(!sz){ int psz = P.sz, msz = M.sz; if(psz){ if(msz>=2 && M[msz-1]*M[msz-2] > P[psz-1]*100 ){ Add(M,msz-1) Add(M,msz-2) }else { Add(P,psz-1) } }else { if(msz>=2){ Add(M,msz-1) Add(M,msz-2) }else ans[sz++] = pzero; } } sort(ans,ans+sz); printf("%d %d",sz,ans[0]); for(int i = 1; i < sz; i++) printf(" %d",ans[i]); putchar(' '); return 0; }