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\n",i,ans);
     }
     return 0;
 }

 

posted @ 2018-04-13 21:18  GHzz  阅读(169)  评论(0编辑  收藏  举报