• BZOJ3571 [Hnoi2014]画框


    我们可以把$(sum A, sum B)$看做平面上的点,那么就是要找到下凸壳上与$y = -x + b$这个直线系上某条支线刚好相切的切点

    现在可以知道下凸壳上最左边的点$X$和最下面的点$Y$

    于是我们可以先找到与直线$XY$距离最远的点$Z$,然后查看答案点是在$XZ$、$YZ$中的哪一段,递归下去就好了

    关于如何计算$Z$:

    经过$X$、$Y$两点的直线$Ax + By + C = 0$,$Z(x_0, y_0)$到它最远,故$frac{|Ax_0 + By_0 + C|} {sqrt{A^2 + B^2}}$最大

    又由于$Z$在$XY$左下,所以等价于$Ax_0 + By_0$最小,而这个是可以用KM做的,于是就做完了

      1 /**************************************************************
      2     Problem: 3571
      3     User: rausen
      4     Language: C++
      5     Result: Accepted
      6     Time:2356 ms
      7     Memory:908 kb
      8 ****************************************************************/
      9  
     10 #include <cstdio>
     11 #include <cstring>
     12 #include <algorithm>
     13   
     14 using namespace std;
     15 typedef long long ll;
     16 const int N = 75;
     17 const ll inf = (ll) 1e18;
     18   
     19 struct point {
     20     int x, y;
     21     point(int _x = 0, int _y = 0) : x(_x), y(_y) {}
     22       
     23     inline point operator -(const point &p) const {
     24         return point(x - p.x, y - p.y);
     25     }
     26     inline ll operator * (const point &p) const {
     27         return 1ll * x * p.y - 1ll * y * p.x;
     28     }
     29 };
     30   
     31 int n;
     32 int a[N][N], b[N][N];
     33 ll w[N][N], slack[N];
     34 ll lx[N], ly[N];
     35 int link[N];
     36 bool vx[N], vy[N];
     37 ll ans;
     38   
     39 inline int read() {
     40     int x = 0, sgn = 1;
     41     char ch = getchar();
     42     while (ch < '0' || '9' < ch) {
     43         if (ch == '-') sgn = -1;
     44         ch = getchar();
     45     }
     46     while ('0' <= ch && ch <= '9') {
     47         x = x * 10 + ch - '0';
     48         ch = getchar();
     49     }
     50     return sgn * x;
     51 }
     52   
     53 bool dfs(int p) {
     54     register int i;
     55     register ll tmp;
     56     vx[p] = 1;
     57     for (i = 1; i <= n; ++i) {
     58         if (vy[i]) continue;
     59         tmp = lx[p] + ly[i] - w[p][i];
     60         if (!tmp) {
     61             vy[i] = 1;
     62             if (link[i] == -1 || dfs(link[i])) {
     63                 link[i] = p;
     64                 return 1;
     65             }
     66         } else slack[i] = min(slack[i], tmp);
     67     }
     68     return 0;
     69 }
     70   
     71 inline point KM() {
     72     static int i, j;
     73     static ll d;
     74     static int resa, resb;
     75     memset(ly, 0, sizeof(ly));
     76     memset(link, -1, sizeof(link));
     77     for (i = 1; i <= n; ++i)
     78         for (lx[i] = -inf, j = 1; j <= n; ++j)
     79             lx[i] = max(lx[i], w[i][j]);
     80     for (i = 1; i <= n; ++i) {
     81         for (j = 1; j <= n; ++j) slack[j] = inf;
     82         while (1) {
     83             memset(vx, 0, sizeof(vx));
     84             memset(vy, 0, sizeof(vy));
     85             if (dfs(i)) break;
     86             for (d = inf, j = 1; j <= n; ++j)
     87                 if (!vy[j]) d = min(d, slack[j]);
     88             for (j = 1; j <= n; ++j)
     89                 if (vx[j]) lx[j] -= d;
     90             for (j = 1; j <= n; ++j)
     91                 if (vy[j]) ly[j] += d;
     92                 else slack[j] -= d;
     93         }
     94     }
     95     for (resa = resb = 0, i = 1; i <= n; ++i)
     96         if (link[i] != -1)
     97             resa += a[link[i]][i], resb += b[link[i]][i];
     98     ans = min(ans, 1ll * resa * resb);
     99     return point(resa, resb);
    100 }
    101   
    102 inline void work(point L, point R) {
    103     register int i, j;
    104     register point p = R - L, mid;
    105     for (i = 1; i <= n; ++i)
    106         for (j = 1; j <= n; ++j)
    107             w[i][j] = p * point(a[i][j], b[i][j]);
    108     mid = KM();
    109     if ((mid - R) * (L - R) <= 0) return;
    110     work(L, mid), work(mid, R);
    111 }
    112   
    113 int main() {
    114     int T, i, j;
    115     point L, R;
    116     T = read();
    117     while (T--) {
    118         n = read(), ans = inf;
    119         for (i = 1; i <= n; ++i)
    120             for (j = 1; j <= n; ++j) a[i][j] = read();
    121         for (i = 1; i <= n; ++i)
    122             for (j = 1; j <= n; ++j) b[i][j] = read();
    123         for (i = 1; i <= n; ++i)
    124             for (j = 1; j <= n; ++j)
    125                 w[i][j] = -a[i][j];
    126         R = KM();
    127         for (i = 1; i <= n; ++i)
    128             for (j = 1; j <= n; ++j)
    129                 w[i][j] = -b[i][j];
    130         L = KM();
    131         work(L, R);
    132         printf("%lld
    ", ans);
    133     }
    134     return 0;
    135 }
    View Code
    By Xs酱~ 转载请说明 博客地址:http://www.cnblogs.com/rausen
  • 相关阅读:
    小程序路由
    机器学习笔记—支持向量机(1)
    用极大似然估计法推出朴素贝叶斯法中的先验概率估计公式
    机器学习笔记—生成学习
    机器学习笔记—再谈广义线性模型
    机器学习笔记—指数分布簇和广义线性模型
    机器学习笔记—Logistic 回归
    机器学习笔记—局部权重线性回归
    机器学习笔记—线性回归
    机器学习笔记1
  • 原文地址:https://www.cnblogs.com/rausen/p/4458677.html
Copyright © 2020-2023  润新知