Luogu 4388 付公主的矩形

Posted czxingchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu 4388 付公主的矩形相关的知识,希望对你有一定的参考价值。

还是挺妙的。

发现对于一个$r$行$c$列的矩阵,穿过的格子数$n = r + c - gcd(r, c)$,题目中其实给定了这个$n$,要我们计算满足这个式子的$r$和$c$的个数。

发现$n$一定要是$gcd(r, c)$的倍数,等式两边可以除掉这个$gcd(r, c)$,变成$n‘ = r‘ + c‘ - 1$。

那么这时候$gcd(r‘, c‘) = gcd(n‘ + 1 - r‘, c‘) = 1$。

根据辗转相减法,有$gcd(n‘ + 1, c‘) = 1$,而满足这个式子的$c‘$的个数恰好是$varphi (n‘ + 1)$。

于是可以开心地计算出$c‘$的总数$sum = sum_{d|n} varphi (d + 1)$。

注意到这时$(n, n)$这一对数只算了一遍,所以最后的答案$ans = (sum + 1) / 2$。

线性筛一波就好啦,时间复杂度$O(n)$。

Code:

技术分享图片
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 1e6 + 5;

int n, pCnt = 0, ans = 0, pri[N], phi[N];
bool np[N];

inline void sieve() {
    phi[1] = 0;
    for(int i = 2; i <= n + 1; i++) {
        if(!np[i]) pri[++pCnt] = i, phi[i] = i - 1;
        for(int j = 1; j <= pCnt && i * pri[j] <= n + 1; j++) {
            np[i * pri[j]] = 1;
            if(i % pri[j] == 0) {
                phi[i * pri[j]] = phi[i] * pri[j];
                break;
            }
            phi[i * pri[j]] = phi[i] * phi[pri[j]];
        }
    }
}

int main() {
    scanf("%d", &n);
    sieve();
    for(int i = 1; i <= n; i++)
        if(n % i == 0) ans += phi[i + 1];
    printf("%d
", (ans + 1) / 2);
    return 0;
}
View Code

 

以上是关于Luogu 4388 付公主的矩形的主要内容,如果未能解决你的问题,请参考以下文章

luogu4389 付公主的背包

[luogu4389]付公主的背包(FFT)

付公主的矩形

LG4389 付公主的背包

付公主的背包

LGP4389付公主的背包