【文文殿下】CF1029F Multicolored Markers

这道题考场上卡了文文相当长的时间,所以写个题解泄泄愤QAQ

题意:给你$a$块红瓷砖,$b$块白瓷砖,在一个无限大的地上拼装,要求整体是一个矩形,并且至少有一种颜色是一个矩形,求最小周长。


题解:

  首先,我们知道,当面积一定时,矩形的形状越接近正方形,周长越小。

  很显然的想到,我们可以给总数$tot$=$a$+$b$开个方,然后去找一个最接近的矩形出来。

  但事实上这个方法是错误的:你无法保证至少有一种颜色的是一个矩形。

  我们首先,要分情况讨论,让$a$是矩形还是让$b$是矩形。当然,我们讨论每个的时候,不约束另一个的形状。

  假设我们保证$a$是矩形,那么我们就要首先找出从$1$到$sqrt{a}$之间所有的$a$的因数,来找到$a$矩形的较短边。

  然后再找总数的较短边。

  我们每找到一个总数的较短边$x$,就要在$a$的因数中,找到最大的一个小于$x$的数字。这一步可以用一个$splay$维护,当然由于是静态的,也可以二分查找。

  但事实上,有一个显而易见的规律:如果我们从小到大枚举$tot$的因数,那么对应的$a$的因数是单调的。所以我们利用这个单调性,缩短到$O(a)$.

  然后对$b$ ,Once More! 找两者的最优解

  参考代码

  

#include <bits/stdc++.h>

#define forn(i, n) for (int i = 0; i < int(n); i++)

typedef long long li;

using namespace std;

const int N = 1000 * 1000;

int lens[N];
int k;

li solve(li a, li b){
    k = 0;
    for (li i = 1; i * i <= b; ++i)
        if (b % i == 0)
            lens[k++] = i;
    
    li ans = 2 * (a + b) + 2;
    li x = a + b;
    int l = 0;
    for (li i = 1; i * i <= x; ++i){
        if (x % i == 0){
            while (l + 1 < k && lens[l + 1] <= i)
                ++l;
            if (b / lens[l] <= x / i)
                ans = min(ans, (i + x / i) * 2);
        }
    }
    
    return ans;
}

int main() {
    li a, b;
    scanf("%lld%lld", &a, &b);
    printf("%lld
", min(solve(a, b), solve(b, a)));
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Syameimaru/p/9548383.html