zoukankan      html  css  js  c++  java
  • HDU4407 Sum 容斥定理

    对于一个数F,设F = p1^e1*p2^e2...*pn^en 那么[1-N]内与其互质的数和与D = p1*p2*...pn是一致的,因为和F、D互质的数都是不含有他们的素因子的数。对于D这个数求[1-N]内有多少个与其互质的数就可用运用容斥定理来求解了。以6为例,首先计算出与2不互质的数,用等差数列公式能够计算出这些满足于2不互质数的和,接着就加上与3不互质的和,最后再减一次与6不互质的和即可。对于那些改变的数,由于数量不是很多,可以单独拿出来进行处理。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<set>
    #include<map>
    #include<cstring>
    #include<vector>
    #include<string>
    #define MAXN 800
    #define LL long long
    using namespace std;
    
    int N, M, rec[50];
    map<int,int>mp;
    bool p[805];
    int pri[805], idx;
    
    inline int gcd(int a, int b) {
        return b ? gcd(b, a % b) : a;
    }
    
    inline void Getprime() {
        idx = -1;
        for (int i = 2; i <= MAXN; ++i) {
            if (!p[i]) {
                pri[++idx] = i;
            }
            for (int j = 0; i * pri[j] <= MAXN; ++j) {
                p[i*pri[j]] = 1;
                if (i % pri[j] == 0) break;
            }
        } 
    }
    
    inline long long cal(int num, int x) {
        if (x == 0) return 0;
        long long ret = 0;
        int cnt = 0, mask;
        int LIM = (int)sqrt(double(num));
        for (int i = 0; pri[i] <= LIM; ++i) {
            if (num % pri[i] == 0) {
                rec[++cnt] = pri[i];
                while (num % pri[i] == 0) {
                    num /= pri[i];
                }
            }
            if (num == 1) break;
        }
        if (num != 1) {
            rec[++cnt] = num;
        }
        mask = 1 << cnt;
        for (int i = 1; i < mask; ++i) { 
            int tsum = 0;
            long long yinzi = 1;
            for (int j = 0; j < cnt; ++j) {
                if (i & (1 << j)) {
                    ++tsum;
                    yinzi *= rec[j+1];
                }
            } 
            if (tsum & 1) {
                long long k = x / yinzi;
                ret += ((yinzi + k * yinzi) * k) >> 1;
            } else {
                int k = x / yinzi;
                ret -= ((yinzi + k * yinzi) * k) >> 1;
            }
        }
        return ret;
    }
    
    inline long long SUM(int x) {
        return ((1 + 1LL * x) * 1LL * x) >> 1;
    }
    
    int main()
    {
        Getprime();
         int T, op, a, b, p;
         map<int,int>::iterator it;
         long long ret;
         scanf("%d", &T);
         while (T--) {
            mp.clear();
            scanf("%d %d", &N, &M);
            for (int i = 1; i <= M; ++i) {
                scanf("%d", &op);
                if (op == 1) { 
                    ret = 0;
                    scanf("%d %d %d", &a, &b, &p);
                    for (it = mp.begin(); it != mp.end(); ++it) {
                        if (it->first != it->second && it->first >= a && it->first <= b) {
                            ret -= gcd(it->first, p) == 1 ? it->first : 0;
                            ret += gcd(it->second, p) == 1 ? it->second : 0;
                        }
                    }
                    ret += SUM(b) - SUM(a-1) - (cal(p, b) - cal(p, a-1));
                    printf("%I64d\n", ret);
                } else {
                    scanf("%d %d", &a, &b);
                    mp[a] = b;
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    不同长度的数据进行位运算
    Linux的sleep()和usleep()的使用和区别
    linux inode已满解决方法
    Debian 系统修改语言设置成英文
    IIS设置问题
    Ajax实现跨域访问的三种方法
    HTML--备忘点
    C#基础---值类型和引用类型
    dapper.net框架使用随笔
    WebService的搭建,部署,简单应用和实体类结合使用
  • 原文地址:https://www.cnblogs.com/Lyush/p/2698448.html
Copyright © 2011-2022 走看看