考虑不限制奇偶的情况,那就是直接排序取前k个的和。
加上奇偶限制:若排序后的前k个的和是偶数,则“显然地”:将其中的最小的奇数替换成未被选择的数中最大的偶数 或者 将其中的最小的偶数替换成未被选择的数中最大的奇数 是最优的。
那么排序之后 就可以预处理出 某个位置左侧最小的奇数、左侧最小的偶数、右侧最大的奇数、右侧最大的偶数,然后就可以O(1)地回答每个询问了。
开long long
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define N 1050001 5 typedef long long ll; 6 #define INF 2147483647 7 int n,a[N],lminj[N],lmino[N],rmaxj[N],rmaxo[N],jnow=INF,onow=INF,m,k; 8 ll sum[N]; 9 bool cmp(const int &a,const int &b){return a>b;} 10 int main() 11 { 12 scanf("%d",&n); 13 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 14 sort(a+1,a+n+1,cmp); 15 for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(ll)a[i]; 16 for(int i=1;i<=n;i++) 17 { 18 if(a[i]&1) jnow=min(jnow,a[i]); 19 else onow=min(onow,a[i]); 20 lminj[i]=jnow; lmino[i]=onow; 21 } jnow=onow=0; 22 for(int i=n-1;i>=1;i--) 23 { 24 if(a[i+1]&1) jnow=max(jnow,a[i+1]); 25 else onow=max(onow,a[i+1]); 26 rmaxj[i]=jnow; rmaxo[i]=onow; 27 } 28 scanf("%d",&m); 29 for(int i=1;i<=m;i++) 30 { 31 scanf("%d",&k); 32 if(sum[k]&1) printf("%lld ",sum[k]); 33 else 34 { 35 ll ans=-1; 36 if(lminj[k]!=INF&&rmaxo[k]!=0) ans=max(ans,sum[k]-(ll)lminj[k]+(ll)rmaxo[k]); 37 if(lmino[k]!=INF&&rmaxj[k]!=0) ans=max(ans,sum[k]-(ll)lmino[k]+(ll)rmaxj[k]); 38 printf("%lld ",ans); 39 } 40 } 41 return 0; 42 }