思路清晰很重要,不然写出来的代码一堆的bug
题意:给你n个数,其中如果x>m,那么之后的d个数就没有作用,问你得到的和最多是多少
思路:一开始以为是dp,然而并不是,直接贪心就可以过了,对于a[i]>m的数放在一个数组里,其他数放在另一个数组里,从大到小排序,求前缀和,分别为a[i]和b[i],之后就是贪心的过程了,假设你可以用i个大于m的数,那么就意味着,你用去了day=(i-1)*(d+1)+1天,为什么这样写,因为首先可以想到把一个数放到最后,那么就是说你有一天用的单独的一天,但其他i-1用的是d+1天(包括自己本身),那么还有剩余的天数,也就是数组b可以用的天数,等于n-day?其实并不然,想想有一个bug,当你的单独成一天的那个位置也对这个数组起了作用的话,你用去的天数就不是(i-1) * (d+1)+1,还需要加上你没有在i-1里被覆盖的大于m的数被最后一个数覆盖了,这么一想好像还挺复杂的,所以说。。。思路要清晰。。
可以这么想,当你算的天数用少了的时候,x小于m的天数就会变多,可以肯定是大于数组b的长度的,所以在这里直接取一个min就可以了也就是min(n-day, lenb),就可以了
思路清晰的代码:
#define int ll
bool cmp(int x, int y){
return x>y;
}
int a[maxn], b[maxn];
signed main(){
int n=read(), d=read(), m=read();
int l1=0, l2=0;
rep(i,1,n){
int x = read();
if(x>m) a[++l1] = x;
else b[++l2] = x;
}
sort(a+1, a+l1+1, cmp);
sort(b+1, b+l2+1, cmp);
rep(i,1,l1) a[i] += a[i-1];
rep(i,1,l2) b[i] += b[i-1];
ll ans = b[l2];
rep(i,1,l1){
int day = (i-1)*(d+1)+1;
if(day > n) break;
ans = max(ans, a[i]+b[min(n-day, l2)]);
}
printf("%lld\n", ans);
return 0;
}
思路不清晰的代码,调了好久的bug。。:
int a[maxn], b[maxn], c[maxn];
signed main(){
// fopen;
int n=read(), d=read(), m=read();
rep(i,0,n-1) a[i]=read();
sort(a, a+n);
int x = n-(upper_bound(a, a+n, m)-a); //这一部分完全就是多余的,根本不需要这么麻烦,+1-1还让我想了有点久,直接在输入那里比较就行了,吐血
rep(i,1,x-1) b[i] = b[i-1]+a[n-i-1];
rep(i,1,n-x) c[i] = c[i-1]+a[n-x-i];
/*rep(i,1,x-1) printf("b[%d]=%lld ", i, b[i]);printf("\n");
rep(i,1,n-x) printf("c[%d]=%lld ", i, c[i]);printf("\n");*/
if(!x){ //这里进行了以下特判其实可以不用,直接ans=c[n-x]就行
printf("%lld\n", c[n]);return 0;
}
ll ans=0;
n--;x--;
int t1 = x/(d+1), t2= min(n/(d+1), x); //这里是相对来说更严谨的地方,大于m的值取的个数肯定是有一个上限和下限的,但之前的代码中并没有,直接是1到lena,然后在循环中进行一下判断
// printf("t1=%d t2=%d\n", t1, t2);
rep(i,t1,t2){
int cnt = n-1ll*i*(d+1);
int tmp = c[min(cnt, n-x)]+b[i]+a[n];
// printf("cnt=%lld tmp=%lld\n", cnt, tmp);
ans = max(ans, tmp);
}
printf("%lld\n", ans);
return 0;
}