容斥二题(HDU4135&4059)

版权声明:蒟蒻的博文,dalao转载标明出处就好吖 https://blog.csdn.net/jokingcoder/article/details/81506381

容斥二题(HDU4135&4059)

A.Co-prime

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description
Given a number N , you are asked to count the number of integers between A and B inclusive which are relatively prime to N .
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1 . The number 1 is relatively prime to every integer.

Input
The first line on input contains T ( 0 < T <= 100 ) the number of test cases, each of the next T lines contains three integers A , B , N where ( 1 <= A <= B <= 10 15 ) and ( 1 <= N <= 10 9 ) .

Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N . Follow the output format below.

Sample Input

2
1 10 2
3 15 5

Sample Output

Case #1: 5
Case #2: 10

Hint
In the first test case, the five integers in range [ 1 , 10 ] which are relatively prime to 2 are [ 1 , 3 , 5 , 7 , 9 ] .

Solution
应该都能看出是容斥,只要我们可以算出 [ 1 , x ] 之间与n互质的数,那 [ a , b ] 之间互质的数就是 [ 1 , b ] [ 1 , a 1 ]
要算出 [ 1 , x ] 之间与n互质的数,只要考虑每个质因子的是否出现即可以为一个数的质因子不会太多,直接压位暴力即可

Code

#include <cstdio>
#define N 1000000000
#define M 1000000

using namespace std;
typedef long long LL;
LL q[M], p[M], cnt;
bool pr[M];

inline void init() {
    for (LL i = 2; i * i < M; ++i)
        if (!pr[i])
            for (LL j = 2; j * i < M; ++j)
                pr[i * j] = 1;
    for (LL i = 2; i < M; ++i) {
        if (!pr[i]) p[++cnt] = i;
    }
}

LL make(LL x, LL y) {
    LL o = y, now = 0;
    if (x == 0) return 0;
    for (LL i = 1; p[i] * p[i] <= o && i <= cnt; ++i) {
        if (o % p[i] == 0) {
            q[++now] = p[i];
            while (o % p[i] == 0) o /= p[i];
        }
    }
    if (o > 1) q[++now] = o;
    LL ans = 0;
    for (LL i = 1; i < (1LL << now); ++i) {
        LL u = 1, c = 0;
        for (int j = 0; j < now; ++j) {
            if (i & (1LL << j)) u *= q[j + 1], c++;
        }
        if (c & 1) ans += x / u;
        else ans -= x / u;
    }
    return (LL)x - ans;
}

int main() {
    init();
    LL T, a, b, n;
    scanf("%lld", &T);
    for (LL cas = 1; cas <= T; ++cas) {
        scanf("%lld%lld%lld", &a, &b, &n);
        printf("Case #%lld: %lld\n", cas, make(b, n) - make(a - 1, n));
    }
    return 0;
}

B.The Boss on Mars

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)

Problem Description
On Mars, there is a huge company called ACM (A huge Company on Mars), and it’s owned by a younger boss.

Due to no moons around Mars, the employees can only get the salaries per-year. There are n employees in ACM, and it’s time for them to get salaries from their boss. All employees are numbered from 1 to n . With the unknown reasons, if the employee’s work number is k , he can get k 4 Mars dollars this year. So the employees working for the ACM are very rich.

Because the number of employees is so large that the boss of ACM must distribute too much money, he wants to fire the people whose work number is co-prime with n next year. Now the boss wants to know how much he will save after the dismissal.

Input
The first line contains an integer T indicating the number of test cases. ( 1 T 1000 ) Each test case, there is only one integer n , indicating the number of employees in ACM. ( 1 n 10 8 )

Output
For each test case, output an integer indicating the money the boss can save. Because the answer is so large, please module the answer with 1 , 000 , 000 , 007 .

Sample Input

2
4
5

Sample Output

82
354
Hint

Hint
Case1: s u m = 1 + 3 3 3 3 = 82
Case2: s u m = 1 + 2 2 2 2 + 3 3 3 3 + 4 4 4 4 = 354

Solution
这题和A题其实并没有本质区别,就是多了一个四次方求和
(我发现最近的最近做到的四次方求和的题特别多,一定要好好补一下
回到正题
本题与题A唯一不同的地方是 a 4 + ( 2 a ) 4 + ( 3 a ) 4 + . . . + ( n a ) 4
其实也只是普通的转换,变成 ( 1 4 + 2 4 + 3 4 + . . . + n 4 ) a 4
唯一需要注意的地方(也是我Debug了一个多小时的地方,因为基本上每个数据都是对的)!!!
给的模数是 1 e 9 + 7 ,我以前做过一道这样的题戳这里
E题的题解
当时题目给的 m 只有 1 e 5 ,乘上30完全不会爆炸,但是 ( 10 9 + 7 ) 30 也并不会炸long long啊???
然而有两个数一乘就会炸了。。。
所以不要偷懒,还是求个逆元吧: 30 关于 10 9 + 7 的逆元可以直接算出来是 233333335
真的 233333333......

Code

#include <cstdio>
#define M 20000
#define PSC 1000000007
#define PP 233333335

using namespace std;
typedef long long LL;
LL q[M], p[M], cnt;
bool pr[M];

inline void init() {
    for (LL i = 2; i * i < M; ++i)
        if (!pr[i])
            for (LL j = 2; j * i < M; ++j)
                pr[i * j] = 1;
    for (LL i = 2; i < M; ++i) {
        if (!pr[i]) p[++cnt] = i;
    }
}

LL make(LL n) {
    LL ans = n % PSC * (n + 1) % PSC * (2 * n + 1) % PSC * ((3 * n % PSC * n % PSC + 3 * n - 1) % PSC) % PSC * PP % PSC;
    return ans;
}

int main() {
    init();
    LL T, a, b, n;
    scanf("%lld", &T);
    for (LL cas = 1; cas <= T; ++cas) {
        scanf("%lld", &n);
        LL o = n, now = 0;
        for (LL i = 1; p[i] * p[i] <= o && i <= cnt; ++i) {
            if (o % p[i] == 0) {
                q[++now] = p[i];
                while (o % p[i] == 0) o /= p[i];
            }
        }
        if (o > 1) q[++now] = o;
        LL ans = 0;
        for (LL i = 1; i < (1LL << now); ++i) {
            LL u = 1, c = 0;
            for (LL j = 0; j < now; ++j) {
                if (i & (1LL << j)) u *= q[j + 1], c++;
            }
            if (c & 1) ans = (ans + make(n / u) * u % PSC * u % PSC * u % PSC * u % PSC) % PSC;
            else ans = (ans - make(n / u) * u % PSC * u % PSC * u % PSC * u % PSC) % PSC;
            if (ans < 0) ans += PSC;
        }
        ans = (make(n) - ans) % PSC;
        if (ans < 0) ans += PSC;
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jokingcoder/article/details/81506381