1 条题解

  • 0
    @ 2026-5-7 23:41:30

    思路

    首先,AABB 只会移动一个,那么,我们分开来算,我们先假定 BB 会动。

    不妨令 AAbb 连边的端点为 x,yx,y。如果有线段 pqpq 能与 xyxy 相交,一定满足如下其中一条规律:

    1. p<xq>yp < x \wedge q > y
    2. p>xq<yp > x \wedge q < y

    发现每一次循环右移一次,只会影响一条端点在 BnB_n 的位置的线段,其余线段相对位置不变。

    BnB_nAA 中的位置为 xx。因为 BnB_n 是在 BB 中的最后一个元素,所以如果有线段能与其所在线段相交,那么只能是满足上述规律中的第 2 种。所以所有以 Ax+1nA_{x + 1 \sim n} 为端点的线段一定与 BnB_n 所在线段相交。

    那么,如果我们将 BB 循环右移一位后,可以发现原本与 BnB_n 相交的线段都不会相交了,即将数量 resres 变为了 res(nx)res - (n - x)

    再来考虑 BnB_n 循环右移到 B1B_1 时会产生新的数量。因为 B1B_1BB 中的第一个元素,所以如果有线段能与其所在线段相交,那么只能是满足上述条件中的第 1 种。所以,所有以 A1x1A_{1 \sim x - 1} 为端点的线段一定与其相交。

    那么,我们将 BB 循环右移一位后,可以发现能新产生 x1x - 1 条线段,即将数量 resres 变为了 res+(x1)res + (x - 1)

    那么结果 resres 将变为 res(nx)+(x1)=resn+2x1res - (n - x) + (x - 1) = res - n + 2x - 1

    接下来只需要处理出 resres 在不动时的结果即可。

    我们将 posipos_i 表示 BBAA 中的位置,可以发现当 i<jposi>posji < j \wedge pos_i > pos_j 时就会产生一条相交的线段对。然后发现本质上就是求 pospos 的逆序对数量,用树状数组算一下即可。

    注意:不要忘了讨论 AA 动的情况。

    code

    #include <bits/stdc++.h>
    #define re register
    #define int long long
    
    using namespace std;
    
    const int N = 1e5 + 10;
    int n,ans,t;
    int arr[N],brr[N],vis[N],pos[N];
    
    inline int read(){
    	int r = 0,w = 1;
    	char c = getchar();
    	while (c < '0' || c > '9'){
    		if (c == '-') w = -1;
    		c = getchar();
    	}
    	while (c >= '0' && c <= '9'){
    		r = (r << 3) + (r << 1) + (c ^ 48);
    		c = getchar();
    	}
    	return r * w;
    }
    
    struct BIT{
    	int tr[N];
    	
    	inline int lowbit(int x){
    		return x & -x;
    	}
    	
    	inline void modify(int x,int k){
    		for (re int i = x;i <= n;i += lowbit(i)) tr[i] += k;
    	}
    	
    	inline int query(int x){
    		int res = 0;
    		for (re int i = x;i;i -= lowbit(i)) res += tr[i];
    		return res;
    	}
    }tree;
    
    inline int f(int *arr,int *brr){
    	for (re int i = 1;i <= n;i++) vis[arr[i]] = i;
    	for (re int i = 1;i <= n;i++) pos[i] = vis[brr[i]];
    	int res = 0,ans = 0;
    	memset(tree.tr,0,sizeof(tree.tr));
    	for (re int i = n;i;i--){
    		res += tree.query(pos[i]);
    		tree.modify(pos[i],1);
    	}
    	ans = res;
    	for (re int i = n;i;i--){
    		res = res - n + 2 * pos[i] - 1;
    		ans = min(ans,res);
    	}
    	return ans;
    }
    
    signed main(){
    	n = read();
    	for (re int i = 1;i <= n;i++) arr[i] = read();
    	for (re int i = 1;i <= n;i++) brr[i] = read();
    	printf("%lld",min(f(arr,brr),f(brr,arr)));
    	return 0;
    }
    
    • 1

    *【树状数组】最少交叉[USACO17FEB] Why Did the Cow Cross the Road I P

    信息

    ID
    6847
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    11
    已通过
    1
    上传者