• bzoj 2301: [HAOI2011]Problem b mobius反演 RE


    http://www.lydsy.com/JudgeOnline/problem.php?id=2301

    设f(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) = i的个数。

    设F(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) % i == 0的个数,很简单的公式就是floor(n / i) * floor(m / i)

    可知gcd(x, y) = k * i也属于F(i)的范围,所以可以反演得到f(i)的表达式。

    算一次复杂度O(n),而且询问区间的时候要拆分成4个区间来容斥,所以总复杂度会达到4 * 5e4 * 5e4 = 1e10

    技巧:(和省赛E题一样的技巧,无奈省赛一直卡E)

    注意到,floor(n / i)的取值,很多是相同的,比如,7 / 2 = 7 / 3

    7 / 4 = 7 / 5 = 7 / 6 = 7 / 7,注意到,值是n / i的,起点是i,终点是n / floor(n / i)

    那么可以把相同的放在一起了,虽然是要两个相同才放一起,就是n / i和m / i,但是还是很好写的。

    注意不要用cout,莫名re,re一小时

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    #include <time.h>
    const int maxn = 5e4 + 20;
    int prime[maxn];//这个记得用int,他保存的是质数,可以不用开maxn那么大
    bool check[maxn];
    int total;
    int mu[maxn];
    void initprime() {
        mu[1] = 1; //固定的
        for (int i = 2; i <= maxn - 20; i++) {
            if (!check[i]) { //是质数了
                prime[++total] = i; //只能这样记录,因为后面要用
                mu[i] = -1; //质因数分解个数为奇数
            }
            for (int j = 1; j <= total; j++) { //质数或者合数都进行的
                if (i * prime[j] > maxn - 20) break;
                check[i * prime[j]] = 1;
                if (i % prime[j] == 0) {
                    mu[prime[j] * i] = 0;
                    break;
                }
    //            if (prime[j] * i > maxn - 20) while(1);
                mu[prime[j] * i] = -mu[i];
                //关键,使得它只被最小的质数筛去。例如i等于6的时候。
                //当时的质数只有2,3,5。6和2结合筛去了12,就break了
                //18留下等9的时候,9*2=18筛去
            }
        }
    }
    int sumMu[maxn];
    LL ask(int n, int m, int k) {
        if (k == 0) return 0;
        n /= k;
        m /= k;
        LL ans = 0;
        int mi = min(n, m);
        int nxt;
        for (int i = 1; i <= mi; i = nxt + 1) {
            nxt = min((n / (n / i)), (m / (m / i)));
            ans += (sumMu[nxt] - sumMu[i - 1]) * 1LL * (n / i) * (m / i);
        }
        return ans;
    }
    void work() {
        int a, b, c, d, k;
    //    cin >> a >> b >> c >> d >> k;
        scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
        LL ans = ask(b, d, k) - ask(d, a - 1, k) - ask(c - 1, b, k) + ask(a - 1, c - 1, k);
        printf("%lld
    ", ans);
    //    cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        initprime();
        for (int i = 1; i <= maxn - 20; ++i) {
            sumMu[i] = sumMu[i - 1] + mu[i];
        }
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code
  • 相关阅读:
    黑色边影,
    拉伸的代码,
    一定是selection的原因啊,要不然呢,
    status bar的差别,
    黄色,
    域名错了,
    node=day4
    PS切片
    移动端插件IScroll.js
    移动web资源概论
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6901676.html
Copyright © 2020-2023  润新知