1. 程式人生 > >hdu 4135 Co-prime (素數打表+容斥原理)

hdu 4135 Co-prime (素數打表+容斥原理)

string tdi eof AR Go data tor tom void

題目鏈接

題意:問從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; }

hdu 4135 Co-prime (素數打表+容斥原理)