zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/rausen/p/4458677.html
Copyright © 2011-2022 走看看