Red-Blue Operations (Hard Version)

· · 题解

ch-translater 来了。

先相信,再相信。

### 先说性质。 >- 每个数在【最终加】(最后一次加)之前,一定比原数小。于是我们要让【最终加】最大。 >- 【最终加】的条件是当前数之前被操作偶数次。 >- 【操作】(对同一个数连续进行两次操作)会令一个数变化 $1$。由上述性质,只会有 $-1$ 【操作】。 ### 考虑将操作反过来。 先对数组里每个数进行【最终加】。 于是将 $a_i$ 从小到大排序,则前 $n$ 次操作最优是让 $a_i+k-i+1$。发现 $k$ 是常量,可以提出来,让最后输出答案时再加 $k$,以降低耦合度。 于是构造数组 $b_i=a_i-i+1$,并记 $b$ 的前缀最小值数组 $p$,再记 $b$ 数组和为 $s$。 这时还剩余 $k-n$ 个操作。 #### 若 $k \bmod 2=n \bmod 2$: 剩下偶数次操作。根据性质,这时会对执行 $(k-n)/2$ 次 【操作】。 前 $n$ 次操作后当前最小值为 $mi=p_n$。 注意这时对非最小值操作不会影响答案。于是可以【操作】 $s-mi\times n$ 次。 【操作】完后,会发现所有数相同了,这时再对 $n$ 个数整体进行【操作】。 答案:$k+mi-\lceil \frac{(k-n)/2-(s-mi\times n)}{n} \rceil$。 #### 若 $k \bmod 2\ne n\bmod 2$: 会多出一次操作。这东西很恶心,会令【最终加】少一次。考虑舍弃 $a_n$ 的【最终加】。 此时最小值为 $mi=\min(p_{n-1}+k,a_n)$。 同时注意 $s$ 的变化。 剩下的计算与 $k \bmod 2=n\bmod 2$ 相同。 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; signed main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int n,q;cin>>n>>q; vector<int> a(n+1),p(n+1,2e9); for(int i=1;i<=n;i++) cin>>a[i]; sort(a.begin()+1,a.end()); p[1]=a[1]; for(int i=2;i<=n;i++) p[i]=min(p[i-1],a[i]-i+1); int s=0; for(int i=1;i<=n;i++) s+=a[i]-i+1; for(int i=1;i<=q;i++) { int k;cin>>k; if(k<n) cout<<min(p[k]+k,a[k+1])<<' ';//只对前 k 个数进行【最终加】 else if(k%2==n%2) cout<<p[n]+k-(int)ceil(max(0ll,(k-n)/2-(s-p[n]*n))*1.0/n)<<' '; else { int mi=min(p[n-1],a[n]-k);//由于最终答案+k,所以把 min(p[n-1]+k,a[n]) 变一下 int _s=s+n-1-k-mi*n;//注意 a[n]-n+1 变为 a[n]-k cout<<mi+k-(int)ceil(max(0ll,(k-n+1)/2-_s)*1.0/n)<<' '; } } } ```