感觉自己的智慧不够,写不出来这题
我的思路是,先排序,然后Bob
肯定是选择x
个最大的数字乘以-1
,Alice
要是不移除元素,就会让Bob
可以用更大的数字,移除元素会让总和变小,到底要不要移除元素,移除多少个元素,如果要移除元素肯定也是移除大的元素,把排序后的最后k+x
个元素拿过来考虑,其他元素是不会影响最终答案的
移除0~k
个元素,有k+1
种选择,只要Alice
做出决定,就可以决定Bob
的决定,所以是不是可以直接枚举出答案,k,x
在2e5
范围内
数组下标不知道咋考虑,假设从n-k-x
枚举到数组末尾,算了一下确实可以表示能被操作的所有元素
然后用一个类似于滑动窗口的思路来做这题嘛(明天再来试试)
不移除相当于在前面元素的基础上加上一些元素,Bob
的操作是前面元素的基础上减去一些元素,所以其实这里的差距是两倍原来的元素
移除的话,差距是两倍Bob
操作的元素再加上移除的元素,移除的话,Bob
操作的元素会变小,所以就是一个贪心策略
是不是要用前缀和来表示
让最后面的几个元素的和最小就可以保证所有元素的总和最大,这就是Alice
的最优策略
但是不知道怎么用代码实现
#include<bits/stdc++.h>using namespace std;const int N=2e5+10;
int a[N];
int s[N];void solve()
{int n,k,x;cin>>n>>k>>x;for(int i=1;i<=n;i++) cin>>a[i];sort(a+1,a+1+n,greater<int>());for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];int ans=-0x3f3f3f3f;for(int i=0;i<=k;i++)ans=max(ans,s[n]-s[min(i+x,n)]-(s[min(i+x,n)]-s[i]));cout<<ans<<endl;
}int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);//cout<<0x3f3f3f3f<<endl;int t;cin>>t;while(t--)solve();return 0;
}
前缀和都想到了,但是没想到是直接维护所有的区间和,其实是可以的,反正只需要遍历一遍,从后往前不好操作,把数组从大往小排序更方便
greater<int>()
是按从大到小排序,默认是从小到大排序,less<int>
是从小到大排序
要把答案定义为负无穷,只是定义为-2e5
还会WA
前缀和查询的式子非常巧妙
从1
到n
有n
个元素,计算公式是n-1+1
每一次计算的时候都需要注意一下
min(i+x,n)
就是解决我的下标越界的困惑的,最后维护答案的式子,前面部分就是不会被修改的部分的和,后面部分是Bob
操作的部分的和