CodeForces - 1343D Constant Palindrome Sum(差分、暴力)

Constant Palindrome Sum

题目大意:

给出长度为\(n\)的数列\(a_i\)\(k\),保证\(a_i \leq k\)。将\(a\)中任意一个数\(a_i\)改成\([1, k]\)中的一个数称为一次操作。问最少经过多少次操作后,\(x = a_i+a_{n-i+1} (i \leq \frac{n}{2})\)全部相等。

思路:

首先考虑暴力枚举\(x\),容易得到一个\(O(nk)\)的算法,时间瓶颈在对\(x\)的枚举之上,我们考虑怎么优化。

手玩一下即可发现,对于每一对\((i, n - i + 1)\),至多进行两次修改。我们假设\(x\)的操作次数为\(cnt[x]\),对于每一对\((i, n - i + 1)\),具体的:

  • 如果\(a[i] + a[n - i + 1] == x\),那么\(cnt[x] += 0\)
  • 如果\(max(a[i], a[n - i + 1]) + 1 \leq x\) && \(min(a[i], a[n - i + 1]) + k \geq x\),除掉等于\(x\)的情况\(cnt[x] += 1\)
  • ELSE, \(cnt[x] += 2\)

不难发现,对于操作次数为\(1\)的pair是连续的一段区间,可以想到使用差分\(O(1)\)的修改这段区间\(x\)的操作次数,最后\(O(k)\)的更新答案。

具体实现上:

\(cnt1[x]\)表示选用\(x\)作为每对pair的结果时,修改一次的pair数量。

差分的每次修改都相当于对\([L:]\)区间进行修改。

Code:
ll n, k, a[N], cnt0[N], cnt1[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T--) {
        //init
        ll ans = INF;
        cin >> n >> k;
        for (int i = 1; i <= (k << 1); i++)
            cnt0[i] = cnt1[i] = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        
        for (int i = 1; i <= n / 2; i++) {
            cnt0[a[i] + a[n - i + 1]]++;
            cnt1[min(a[i], a[n - i + 1]) + 1]++, cnt1[max(a[i], a[n - i + 1]) + k + 1]--;
            cnt1[a[i] + a[n - i + 1]]--, cnt1[a[i] + a[n - i + 1] + 1]++; //去掉修改次数为0
        }
        for (int i = 2; i <= (k << 1); i++) { //枚举答案
            cnt1[i] += cnt1[i - 1];
            ckmin(ans, cnt1[i] + 2ll * (n / 2 - cnt0[i] - cnt1[i]));
        }
        cout << ans << "\n";
    }
    return 0;
}
posted @ 2021-08-18 23:02  Nepenthe8  阅读(31)  评论(0编辑  收藏  举报