• P6860 象棋与马 杜教筛


    P6860 象棋与马 杜教筛

    题意

    有一个无限大的棋盘,有一个马最初在((0,0)),它的每步可以走一个(a imes b)的矩形,即能够走到((x pm a,y pm b),或者(x pm b,y pm a))

    若马通过上述移动方式可以达到棋盘中任意一点,那么(p(a,b) = 1),否则(p(a,b) = 0)

    给出(T)组询问,每组询问会给出一个正整数(n),求出

    [(sum_{a=1}^nsum_{b=1}^np(a,b))mod2^{64} ]

    [n imes T leq 10^{11}\ T leq 5 ]

    分析

    走到棋盘的充要条件是能够走到((1,0))

    如果不能走到((1,0)),显然无法走到棋盘的任一点,如果能走到((1,0)),显然可以走到棋盘的任意位置

    由于只有本质不同的4种走法

    • ((a,b))
    • ((b,a))
    • ((-a,b))
    • ((-b,a))

    走到((1,0))的充要条件是

    [x_1 cdot a + x_2 cdot b - y_1 cdot a - y_2 cdot b = 1\ x_1 cdot b + x_2 cdot a + y_1 cdot b + y_2 cdot a = 0 ]

    上下相加,有

    [(x_1+ x_2 - (y_1 - y_2)) a + (x_1 + x_2 + (y_1 - y_2))b = 1 ]

    [(x - y)a + (x + y) b = 1 ]

    可见

    [(a,b) = 1\ ]

    由于$(x + y) (与)(x - y)$必奇偶性同,且必全为奇数,若是偶数,显然右边不等于1

    可以得出a,b奇偶性不同,若相同,右边不等于0

    下面进行对答案讨论

    (a)为偶数,只需要求出为奇数且与(a)互质的数,答案显然是(phi(a))

    (a)为奇数,只需要求出为偶数且与(a)互质的数,答案为(frac{phi(a)}{2}),这是因为,(a)为奇数时,与它互质的数总是成对出现的

    这是发现答案就是

    [ans = sumphi(i) + sum_{i 为偶数}phi(i) ]

    由于(n)达到1e11,这就成为了杜教筛的模板题

    至于后面那一坨,考虑用递归式处理

    [S(n) = sum phi(i)\ ans(n) = S(n) + ans(n / 2) ]

    用到的欧拉函数性质

    [a \% 2 == 1,phi(2a) = phi(a)\ a \% 2== 0,phi(2a) = 2phi(a) ]

    代码

    map<ull, ull> Sphi;
    
    const int M = 1e7 + 5;
    ull prime[M], vis[M], phi[M], s[M], n, m;
    
    void init() {
        phi[1] = 1;
        for (re int i = 2; i <= M - 5; i++) {
            if (!vis[i]) {
                vis[i] = i;
                prime[++m] = i;
                phi[i] = i - 1;
            }
            for (re int j = 1; j <= m && prime[j] *i <= M - 5; j++) {
                if (prime[j] > vis[i]) break;
                vis[i * prime[j]] = prime[j];
                phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]);
            }
        }
        for (re int i = 1; i <= M - 5; i++) {
            if (i & 1) s[i] = phi[i << 1] / 2;
            else s[i] = phi[i];
            s[i] += s[i - 1];
            phi[i] += phi[i - 1];
        }
    }
    
    ull getphi(ull n) {
        if (n <= M - 5)return phi[n];
        if (Sphi[n]) return Sphi[n];
        ull res = 0;
        if (n % 2 == 0) res = n / 2 * (n + 1);
        else res = (n + 1) / 2 * n;
        for (ull l = 2, r; l <= n; l = r + 1) {
            r = n / (n / l);
            res -= (r - l + 1) * getphi(n / l);
        }
        return Sphi[n] = res;
    }
    
    ull S(ull n) {
        if (n <= 1) return 0;
        return getphi(n) + S(n / 2);
    }
    
    int main() {
        init();
        int T = readint();
        while (T--) {
            n = readull();
            printf("%llu
    ", S(n));
        }
    }
    
  • 相关阅读:
    声明式事务编程
    PlatformTransactionManager
    编码式事务
    事务的ACID
    struts2的工作原理
    通过Callable接口实现多线程
    Struts2 标签
    Struts2基础
    MySQL性能优化(十)-- 主从复制(一主多从)
    JVM学习(一)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13893925.html
Copyright © 2020-2023  润新知