Cow Checkups (USACO Silver 2025 January)

Cow Checkups (USACO Silver 2025 January)

题目复述:给定aia_i, bib_i (i,ai,bi5105i, a_i, b_i \leq 5 \cdot 10^5), 对于所有1lrn1 \leq l \leq r \leq n,将al,al+1,...,ara_l, a_{l+1}, ..., a_r反转,然后数有多少个ii,使得bi=aib_i=a_i,求所有l,rl,r组合下的个数之和。

这是一道Prefix sum题。可以看到这个题对于复杂度要求比较高,仅仅能O(1)\mathcal{O}(1)计算一个范围(l,r)(l,r)的贡献都不够。我们需要寻找对所有位置扫描一遍,然后对每个位置都能O(1)\mathcal{O}(1)计算对最终结果的贡献的算法。

我们考虑每个ai=bja_i=b_j的一对位置对,cijc_{ij}为这一对数字对最终的结果的贡献。我们观察,对于固定的iicijc_{ij}随着jj的变化,是分段常数或分段线性的,分段点在j=ij=ij=Nij=N-i

L=min(i,ni)L=\min(i,n-i), R=max(i,ni)R=\max(i,n-i),那么cijc_{ij}可以分成四种情况:

  1. 0j<L0 \leq j < L: cij=j+1c_{ij} = j+1
  2. LjRL \leq j \leq R: cij=L+1c_{ij} = L+1
  3. R<jN1R < j \leq N-1: cij=Njc_{ij} = N-j
  4. 如果i=ji = j,除以上之外,ai,bia_i, b_i还在[l,r][l,r]区间不包含ii时产生贡献: cijc_{ij} += i(i+1)/2+(N1i)(Ni)/2i*(i+1)/2 + (N-1-i)*(N-i)/2

有了这个之后,我们可以对ii循环,用prefix sum来O(1)\mathcal{O}(1)计算对于这个ii的所有jjcijc_{ij}的和。计算方法如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
 
int n;
int a[500005], b[500005];
ll left[500005];       // left[x] is the sum of j+1 for all b[j]=x, to the left of i
ll right[500005];      // right[x] is the sum of N-j for all b[j]=x, to the right of N-i
ll mid[500005];
ll ans;
 
int main() {
    scanf("%d",&n);
    for(int i=0;i<n;++i) 
        scanf("%d", &a[i]);
    for(int i=0;i<n;++i) {
        scanf("%d", &b[i]);
        mid[b[i]]++;
    }
    
    for (int i = 0; i < n; i++) {
        int L = min(i, n-i-1), R = max(i, n-i-1);
 
        ans += left[a[i]] + right[a[i]];
        if (a[i] == b[i])
            ans += (ll)i*(i+1)/2 + (ll)(n-1-i)*(n-i)/2;
        ans += mid[a[i]] * (L+1);
 
        if (i+1 <= n-i-2) {         // i and N-i-1 are added
            left[b[i]] += i+1;
            right[b[n-i-1]] += i+1;
            mid[b[i]]--;
            mid[b[n-i-1]]--;
        } else if (i >= n-i-1) {    // N-i-2 and i+1 is removed
            left[b[n-i-2]] -= n-i-1;
            right[b[i+1]] -= n-i-1;
            mid[b[i+1]]++;
            mid[b[n-i-2]]++;
        }
    }
    printf("%lld\n",ans);
 
    return 0;
}