zoukankan      html  css  js  c++  java
  • hdu 4135 Co-prime (素数打表+容斥原理)

    题目链接

    题意:问从A到B中与N互素的个数。

    题解:

    利用容斥原理:先求出与n互为素数的个数。

    可以先将 n 进行素因子分解,然后用区间 x 除以 素因子,就得到了与 n 的 约数是那个素因子的个数,然后每次这样求一遍,但是发现有重 复的:举个例子 [1,10] 区间中与 6 互素的个数,应该是 10−(10/2+10/3)+(10/6)
    然后利用二进制枚举子集个数,奇数加偶数减。
    具体看代码:
    #include <stdio.h>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #include <map>
    #include <list>
    #include <utility>
    #include <set>
    #include <algorithm>
    #include <deque>
    #include <iomanip>
    #include <vector>
    #define mem(arr, num) memset(arr, 0, sizeof(arr))
    #define _for(i, a, b) for (int i = a; i <= b; i++)
    #define __for(i, a, b) for (int i = a; i >= b; i--)
    #define IO                       
        ios::sync_with_stdio(false); 
        cin.tie(0);                  
        cout.tie(0);
    using namespace std;
    typedef long long ll;
    typedef vector<int> vi;
    const ll INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const int N = 20 + 5;
    const int maxn = 1000000+5;
    bool vis[maxn+1000000];  
    int fac[maxn/100+5];
    int prime[maxn],n; 
    int num = 0; 
    void getprime()  
     {  
         memset(vis, false, sizeof(vis));  
         for (int i = 2; i <= maxn; ++i)  
         {  
             if ( !vis[i] )  prime[++num] = i;  
             for (int j = 1; j <= num && i * prime[j] <= n;  j++)  
             {  
                 vis[ i  *  prime[j] ]  =  true;  
                 if (i % prime[j] == 0) break;  
             }  
         }  
     }
     int cnt = 0;
     void f(ll x) {
         cnt = 0;
         for(int i = 1; prime[i]*prime[i] <=x && i <=num; i++) {
             if(x%prime[i]==0){
                 fac[++cnt] = prime[i];
                 while(x%prime[i]==0) x /= prime[i];
             }
         }
         if(x > 1) fac[++cnt] = x;
     }
     ll solve(ll x) { //利用二进制处理子集,奇数加偶数减。
         ll ans = 0;
         for(int i = 1; i < ((ll)1 << cnt); i++) {
             int tmp = 1,sum = 0;
             for(int j = 0; j < cnt;j++){
                 if(i&((ll)1<<j))sum++, tmp *= fac[j+1];
             }
             if(sum&1) ans += x/tmp;
             else ans -= x/tmp;
         }
         return ans;
     }
     int main() {
         int T;
         ll ans = 0,A,B,N;
         scanf("%d",&T);
         getprime();
         for(int i = 1; i <= T; i++){
             scanf("%lld%lld%lld",&A,&B,&N);
             f(N);
             ans = B - solve(B) - ((A - 1) - solve(A-1));
             printf("Case #%d: %lld
    ",i,ans);
         }
         return 0;
     }
    宝剑锋从磨砺出 梅花香自苦寒来
  • 相关阅读:
    Neural Collaborative Filtering 神经网络协同过滤
    pyspark(一) 常用的转换操作
    HO引擎近况20210315
    LeetCode–前 K 个高频元素
    常用十大算法(七)— 克鲁斯卡尔算法
    常用十大算法(六)— 普里姆算法
    LeetCode–数值的整数次方
    LeetCode–二叉树的层次遍历 II
    常用十大算法(五)— 贪心算法
    LeetCode–二进制中1的个数
  • 原文地址:https://www.cnblogs.com/GHzcx/p/8824035.html
Copyright © 2011-2022 走看看