POJ 2773 Happy 2006(容斥原理+二分)
题意:找和m互质的第k个数。
容斥原理可以快速求出某个范围内,和m不互斥的个数,显然可以求出某个范围内互质的个数,所以只要取一个很大的end,二分即可,写二分的时候开始按普通的写的,发现不对,要找第一个出现的数才是结果,取end和容斥的模版敲错一点,查数据查出了错,4Y。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 using namespace std; 5 #define ll __int64 6 int prim[1001]; 7 ll judge(ll x,int len)//容斥求出1-x范围内和m的互质的个数 8 { 9 int i,j,cat; 10 ll tem,ans = 0; 11 for(i = 1;i < 1<<len;i ++) 12 { 13 cat = 0; 14 tem = 1; 15 for(j = 0;j <= len-1;j ++) 16 { 17 if(i&(1<<j)) 18 { 19 cat ++; 20 tem *= prim[j]; 21 } 22 } 23 if(cat%2) 24 { 25 ans += x/tem; 26 } 27 else 28 { 29 ans -= x/tem; 30 } 31 } 32 return x-ans; 33 } 34 int main() 35 { 36 int m,k,i,len; 37 ll end,str,mid; 38 while(scanf("%d%d",&m,&k)!=EOF) 39 { 40 len = 0; 41 int num = (int)sqrt(m+0.5); 42 for(i = 2;i <= num;i ++) 43 { 44 if(m%i == 0) 45 { 46 prim[len++] = i; 47 while(m%i == 0) 48 m = m/i; 49 } 50 if(m == 1) break; 51 } 52 if(m != 1) prim[len++] = m; 53 str = 1; 54 end = 1e13;//开始开小了 55 while(str < end) 56 { 57 mid = (str+end)/2; 58 ll key = judge(mid,len); 59 if(key < k) 60 str = mid+1; 61 else 62 end = mid; 63 } 64 printf("%I64d\n",str); 65 } 66 return 0; 67 }