zoukankan      html  css  js  c++  java
  • 松鼠聚会

    松鼠聚会

    题意:网格图,有(n)个小松鼠,每个小松鼠到周围八个点的距离为(1),选定一个小松鼠的位置,是的所有松鼠到这个位置的最小路程和。

    数据范围:

    (0 le n le 1e5 \,\, -10^9 le xle 10^9)

    解法:

    题意中两个松鼠的最大距离即为切比雪夫距离:两个点横纵坐标之差的较大值

    曼哈顿距离:两个点横纵坐标的差的绝对值之和

    (OI)常用套路:

    将一个点的坐标((x,y))变为((x + y, x - y)) 后,原坐标系中的曼哈顿距离 = 新坐标系中的切比雪夫距离

    反过来,将一个点的坐标((x,y))变为((frac{x+y}{2},frac{x-y}{2}))后,原坐标系中的切比雪夫距离 = 新坐标系中的曼哈顿距离

    这样我们就可以将原问题进行转化

    不妨将转化后的(x,y)坐标进行排序,对一个点(k)答案就是统计(x)坐标:(x[k] imes t-sum_{i=1}^tx[i](x[t] < x[k]) +sum_{i=k+1}^{n}x[i]- x[k] imes t),统计(y)坐标同理

    所以我们可以采用前缀和优化:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define maxn 100100
    #define ll long long
    ll x1[maxn], y1[maxn];
    ll x2[maxn], y2[maxn];
    ll sumx[maxn], sumy[maxn];
    int n;
    int query1(ll x)
    {
        int l = 1, r = n, ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(x2[mid] <= x)
            {
                ans = mid;
                l = mid + 1;
            }
            else r = mid - 1;
        }
        return ans;
    }
    int query2(ll y)
    {
        int l = 1, r = n, ans = 0;
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(y2[mid] <= y)
            {
                ans = mid;
                l = mid + 1;
            }
            else r = mid - 1;
        }
        return ans;
    }
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            x1[i] = x2[i] = x + y;
            y1[i] = y2[i] = x - y;
        }
        sort(x2 + 1, x2 + n + 1);
        sort(y2 + 1, y2 + n + 1);
        for(int i = 1; i <= n; i++)
        {
            sumx[i] = sumx[i - 1] + x2[i];
            sumy[i] = sumy[i - 1] + y2[i];
        }
        ll ans = 1e15;
        for(int i = 1; i <= n; i++)
        {
        	//printf("x1[%d] = %d y1[%d] = %d
    ", i, x1[i], i, y1[i]);
            ll sum = 0;
            int x = query1(x1[i]), y = query2(y1[i]);
            sum += x * x2[x] - sumx[x] + sumx[n] - sumx[x - 1] - (n - x + 1) * x2[x];
            sum += y * y2[y] - sumy[y] + sumy[n] - sumy[y - 1] - (n - y + 1) * y2[y];
            ans = min(ans, sum);
        }
        printf("%lld
    ", ans >> 1);
        return 0;
    }
    
  • 相关阅读:
    css将元素float和textalign方向一致时
    Asp.Net细节性问题技巧精萃
    ajax单个元素中实现多个回调函数
    javascript实现Observer模式来管理多个事件回调
    管闲事的小明
    字符串扩展
    (转的)计算组合数——整数拆分
    数学题杭电1002A+B。。。交了七遍,五遍竟然是没删除测试时候的输出= =。。。。
    快速排序。。。注意快速排序不适宜解决有重复数据的排序
    哈希查找统计元音
  • 原文地址:https://www.cnblogs.com/Akaina/p/11685101.html
Copyright © 2011-2022 走看看