思路:
- 首先,观察到,一个点修改奇数次,一定是增大。修改偶数次,一定是会减小,且最少也是-1.
- 注意到只要操作过偶数次,这个值已经有所减少,那么你后面加一次也不能达到最大效益了,即如果要使一个数尽可能被加大,那么只加一次是最优的(比如加k,如果第一次加是+k,如果第三次才加,至多也只是+k-1)
- 我们如何最大化那个最小的数?显然是把最大数值加给最小的,次大给次小,所以先给数值排序(小到大)
- 分析n与k的关系
- 如果k<=n,显然可以每个数都只操作一次
- 如果k>n,我们还是希望每个数都能加上k,k-1....k-n+1这前n大的数。
- 当然,前提是你要保证他们都是加的,即每个数各自加上上述的数时必须被操作了偶数次(保证是红色)。所以(k-n)mod 2=0即可n个数都加上,如果mod 2=1,则只有前n-1个数可以
- 也就是说,我们现在就剩如何分配剩余的(k-n)/2对-1了(这里的-1对数举(k-n)mod 2=0时的情况),显然,-1可以先分配给那些大于最小值的数承担。如果承担完了还有剩,那么接下来就是n个数一起减少(最后记得向上取整)
- 我们每次这么寻找修改后的最小值呢,发现a[i]如果被修改,那么他的新值就是a[i]'=a[i]-i+1+k。因为一次询问k是固定的,我们可以维护b[i]=a[i]-i+1数组的最小值,显然后面只需比较该最小值+k即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 3e5 + 10;
int a[N],min1[N],b[N];
void mysolve()
{
int n,q;
cin>>n>>q;
for(int i=1; i<=n; ++i)cin>>a[i];
sort(a+1,a+1+n);
min1[1]=b[1]=a[1];
a[n+1]=llINF;
int sum=b[1];
for(int i=2; i<=n; ++i)b[i]=a[i]-i+1,min1[i]=min(b[i],min1[i-1]),sum+=b[i];//min维护b数组最小值,sum记录全部修改后的数的值的和
int k;
while(q--)
{
cin>>k;
if(n==1)//因为我们处理时常常需要至少2个位置,所以1特判处理比较容易
{
cout<<a[1]-k/2+(k&1?k:0)<<" ";
continue;
}
if(k<=n)cout<<min(min1[k]+k,a[k+1])<<" ";//k<=n答案就是修改了的最小值+k与未修改的最小值(显然a[k+1]~a[n]最小值是a[k+1],排序了)
else
{
int tmp=k-n+1;
if((k-n)%2==0)
{
tmp--;
tmp/=2;//看成一对数(-1)处理
int res=sum+n*k-n*(min1[n]+k);//n个数都有加k,他们的所以值和就是sum+n*k,他们的最小值就是min1[n]+k,我们把那些大的可以承担的数先去抵消-1
tmp=max(tmp-res,0ll);
cout<<min1[n]+k-(tmp+n-1)/n<<" ";//向上取整
}
else
{
int minn=min(min1[n-1]+k,a[n]);
int res=sum+n-1+(n-1)*k-n*minn;//只有n-1个数有+k
tmp/=2;
tmp=max(tmp-res,0ll);
cout<<minn-(tmp+n-1)/n<<" ";
}
}
}
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
//cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}