IEEEXtreme 10.0 - Inti Sets


這是 meelo 原創的 IEEEXtreme極限編程大賽題解

 

Xtreme 10.0 - Inti Sets

題目來源 第10屆IEEE極限編程大賽

https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/inti-sets

 

In order to motivate his Peruvian students, a teacher includes words in the Quechua language in his math class.

Today, he defined a curious set for a given positive integer N. He called this set, an Inti set, and defined it as the set of all positive integer numbers that have the number 1 as their single common positive divisor with number N.

The math class about Inti sets was amazing. After class, the students try to challenge to teacher. They each ask questions like this: "Could you tell me the sum of all numbers, between A and B (inclusive), that are in the Inti set of N?"

Since the teacher is tired and he's sure that you are the best in class, he wants to know if you can help him.

Input Format

The first line of input contains an integer Q, 1 ≤ Q ≤ 20, representing the number of students. Each of the next Qlines contain three space-separated integers NA and B, which represent a query.

Constraints

1 ≤ A ≤ B ≤ N ≤ 10^12

Output Format

The output is exactly Q lines, one per student query. For each query you need to find the sum of all numbers between A and B, that are in the Inti set of N, and print the sum modulo 1000000007.

Sample Input

2
12 5 10 
5 1 4

Sample Output

12
10

Explanation

In the sample input, Q = 2, so you have to answer two questions:

In the first question N = 12, A = 5 and B = 10. So you have to find the sum of all numbers between 5 and 10, that are in the Inti set of 12.

Inti set ( 12 ) = { 1, 5, 7, 11, 13, ... }

2 and 4 are not in the Inti set (12) because 12 and these numbers are also divisible by 2.

3 and 9 are not in the Inti set (12) because 12 and these numbers are also divisible by 3.

The numbers in the Inti set, which are in the query's range, are 5 and 7, so answer is ( 5 + 7 ) MOD 1000000007 = 12

In the second question, the numbers in the Inti set of 5 between 1 and 4 are: 1, 2, 3, 4; so the answer is ( 1 + 2 + 3 + 4 ) MOD 1000000007 = 10

 

題目解析

顯然直接求和會超時,可以用容斥原理解決。

用sumOver(5, 10, 1)表示區間[5,10]內為1倍數的數

由於12的質因數為2, 3

sum(區間[5, 10]內與12互質的數) = sumOver(5, 10, 1) - sumOver(5, 10, 2) - sumOver(5, 10, 3) + sumOver(5, 10, 6)

 

可以通過遍歷區間[0,2^2)的每一個數來遍歷所有因式的組合,

二進制數形式每一位代表是否存在該因數,1代表存在,0代表不存在,

因數的個數為偶數意味着和需要加上,為奇數意味着需要減去

00代表因數為1, 01代表因數為3, 10代表因數為2, 11代表因數為6

 

注意需要使用取余運算避免溢出。 

 

復雜度分析

如果有c個質因數,那么需要求2^c個數的和

求每一個和需要常數時間O(1)

數N,至多只有一個大於sqrt(N)的質因數,因此質因數的個數不超過log(sqrt(N))+1

總復雜度為O(sqrt(N))

 

 

程序

C++

 

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

#define MAXN 1000000007

// 區間[a,b]內,所有為x倍數數的和
long long sumOver(long long a, long long b, long long x) {
    long long aa = (a + x - 1) / x; // 上取整
    long long bb = b / x; // 下取整
    
    long long sum; // sum會超過long long的表示范圍
    if( (aa + bb) % 2 == 0) {
        sum = (((aa + bb) / 2) % MAXN) * ((bb - aa + 1) % MAXN);
    } else {
        sum = ((aa + bb) % MAXN) * (((bb - aa + 1) / 2 ) % MAXN);
    }
    
    return ((sum % MAXN) * (x % MAXN)) % MAXN;
}

// 求不大於max的所有素數
// 使用篩選法
void getPrimes(vector<long long> &primes, long long max) {
    vector<bool> nums(max, 0);
    for(long long i=2; i<max; i++) {
        if(nums[i] == false) {
            primes.push_back(i);
            for(int n=2*i; n<max; n+=i) {
                nums[n] = true;
            }
        }
    }
}

// 對數x進行質因數分解
void getFactors(long long x, vector<long long> &factors, vector<long long> &primes) {
    int i = 0;
    while(x > 1 && i < primes.size()) {
        if(x % primes[i] == 0) {
            factors.push_back(primes[i]);
            while(x % primes[i] == 0) x /= primes[i];
        }
        i++;
    }
    // 小於10^12的數最對有一個大於10^6的質因數
    if(x > 1) {
        factors.push_back(x);
    }
}

int main() {
    /* Enter your code here. Read input from STDIN. Print output to STDOUT */   
    vector<long long> primes;
    getPrimes(primes, 1000000);
    
    int T;
    cin >> T;
    for(int t=0; t<T; t++) {
        long long x, a, b;
        cin >> x >> a >> b;
        long long result = 0;
        vector<long long> factors;
        getFactors(x, factors, primes);
        
        int factorCount = factors.size();
        long long binMax = (long long)1 << factorCount;

        // 遍歷所有的質因數組合
        for(long long bin=0; bin<binMax; bin++) {
            long long factor = 1;
            int factorC = 0;
            for(int i=0; i<factorCount; i++) { 
                if( (bin >> i) & 1 ) {
                    factor *= factors[i];
                    factorC ++;
                }
            }

            if(factorC % 2 == 0) {
                result = (result + sumOver(a, b, factor) + MAXN) % MAXN;
            }
            else {
                result = (result - sumOver(a, b, factor) + MAXN) % MAXN;
            }
        }
        
        cout << result << endl;
    }
    
    return 0;
}

 

博客中的文章均為 meelo 原創,請務必以鏈接形式注明 本文地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM