洛谷P1966 火柴排队(cdq分治 + 逆序对)

2020.6.8
练二分了当然要练练分治,这些基础的处理手段真的还是蛮好用的。

这道题是问ai 和bi的平方和最小,最少需要的相邻的交换次数。手动模拟了一下感觉没什么思路。但是后来注意到每次只能移动相邻的。要想差值的平方和最小自然是两边根据值的大小排好序了对应的下标所指代的元素之差使得差值的平方和最小,顺便记录对应的下标。将用下标建立数组,按照下标将排好序的b的下标投射到a去。然后用类似于归并排序逆序对方法求逆序数就行了,因为我们已经对值的大小分别排好了序,任何不在自己下标上的元素都需要被移动到相应的位置上。所以没有在大小即为需要移动的次数。边跑边取模就行了。

代码:

#include 
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair
#define rep(i, a, b) for(int i = a; i <= b ; ++i)
#define per(i, a, b) for(int i = b ; i >= a ; --i)
#define mint(a,b,c) min(min(a,b), c)
#define MOD 998244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
     
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){
     if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){
     x = x * 10 + s - '0';s = getchar();}
    return x * sign;
}//快读
void write(ll x){
     
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n;
pi(int,int)a[limit],b[limit];
int f[limit],g[limit];//f->g映射
const int mod = 1e8 - 3;
ll ans;
void merge_sort(int l, int r){
     
    if(l == r)return;
    int mid = l + (r - l) / 2;
    merge_sort(l, mid);
    merge_sort(mid + 1, r);//归并
    int i = l, j = mid + 1;
    int it = l;//从l开始sort
    while(i <= mid && j <= r){
     
        if(f[i] <= f[j]){
     
            g[it++] = f[i++];
        }else{
     
            g[it++] = f[j++];
            ans += (mid - i + 1);
            ans %= mod;
        }
    }
    while (i <= mid){
     
        g[it++] = f[i++];
    }
    while (j <= r){
     
        g[it++] = f[j++];
    }
    rep(d ,l, r){
     
        f[d] = g[d];
    }
}
int cmp(pi(int,int) x , pi(int,int) y){
     
    return x.first < y.first;
}
int main() {
     
#ifdef LOCAL
    FOPEN;
#endif
    n = read();
    rep(i ,1, n)a[i].first = read(), a[i].second = i;
    rep(i ,1, n)b[i].first = read(),b[i].second = i;
    stable_sort(a + 1 , a + 1 + n,cmp);
    stable_sort(b + 1, b + 1 + n, cmp);
    rep(i ,1, n){
     
        f[b[i].second] = a[i].second;
    }
    ans = 0;
    merge_sort(1,n);
    write(ans % mod);
    return 0;
}

这是tg的题,另一个usaco的蓝题我今天写挂了,然后暴力一发入魂。。。。。。

你可能感兴趣的:(二分,分治,洛谷p1966,火柴排队,cdq分治,逆序对,acm/oi)