zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    集合赋值及for循环删除符合条件的元素
    shiro系列12:rememberme(记住我)
    shiro系列11:缓存
    shiro系列10:会话管理
    shiro系列8:授权源码解析
    shiro系列7:拦截器
    shiro系列6:授权
    shiro系列5:Realm
    shiro系列4:认证源码解析
    shiro系列3:MD5盐值加密认证流程
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9571420.html
Copyright © 2011-2022 走看看