HDU - 4135 Co-prime

来源:互联网 发布:豆浆机哪款好用 知乎 编辑:程序博客网 时间:2024/06/11 14:28

/*

我觉得这道题最给力的地方是帮我想清楚了一件事,就是如何将一个数字n中的因子全部分离出来。

1.首先筛选出sqrt(n)中所有的素数

2.随后用得到的素数一个个去试除n,当n%prime==0时,就除尽所有的素数

3.最后如果得到的n大于1,说明最后剩余的也是一个素数,应该被加入素因子集合中

可以考虑取21的所有素因子的过程

*/

1.题面

http://acm.hdu.edu.cn/showproblem.php?pid=4135

2.题意

给你区间[a,b],和一个数n,求[a,b]之间和n互素的数字的个数。

3.思路

基本就是提取出公因子,然后根据容斥定理获得答案.

如果先使用线性素数筛预处理出素数的话,会更快.

4.代码

/*****************************************************************    > File Name: Cpp_Acm.cpp    > Author: Uncle_Sugar    > Mail: uncle_sugar@qq.com    > Created Time: 2016年05月05日 星期四 21时25分08秒*****************************************************************/# include <cstdio># include <cstring># include <cctype># include <cmath># include <cstdlib># include <climits># include <iostream># include <iomanip># include <set># include <map># include <vector># include <stack># include <queue># include <algorithm>using namespace std;const int debug = 1;const int size  = 100000 + 10; const int INF = INT_MAX>>1;typedef long long ll;bool isprime[size];ll prime[size];int prim_size;void PrimeTable(){fill(isprime,isprime+size,true);prim_size = 0;isprime[0] = isprime[1] = false;for (int i=2;i<size;i++){if (isprime[i])prime[prim_size++] = i;for (int j=0;j<prim_size&&prime[j]*i<size;j++){isprime[i*prime[j]] = false;if (i%prime[j]==0)break;}}}ll factor[size];int fact_size = 0;void getfactor(ll n){fact_size = 0;int lmt = (int)sqrt(n)+1;for (int i=0;i<prim_size&&prime[i]<=lmt;i++){if (n%prime[i]==0){while (n%prime[i]==0){n /= prime[i];}factor[fact_size++] = prime[i];}if (n==1)break;}if (n>1)factor[fact_size++] = n;}ll coprime[size];int coprim_size;ll getcoprime(ll n){coprime[0] = 1;coprim_size = 1;ll ans = 0;for (int i=0;i<fact_size;i++){int t = coprim_size;for (int j=0;j<coprim_size;j++){coprime[t++] = coprime[j]*factor[i]*(-1);}coprim_size = t;}for (int i=0;i<coprim_size;i++){ans += n/coprime[i];}return ans;}int main(){std::ios::sync_with_stdio(false);cin.tie(0);int i,j;int T,ncase=0;cin >> T;PrimeTable();while (T--){ll a,b,c;cin >> a >> b >> c;getfactor(c);cout << "Case #" << ++ncase << ": "<< getcoprime(b) - getcoprime(a-1) << endl;}return 0;}

上面的getcoprimer函数还有另一种写法,个人感觉更符合容斥定理的公式.

ll getcoprime(ll n){int T = (1<<fact_size);ll ret = 0;while (T--){int flag = 0;ll s = 1;for (int i=0;i<fact_size;i++){if (T&(1<<i)){flag ^= 1;s *= factor[i];}}if (flag)ret -= n/s;}else {ret += n/s;}}return ret;}



0 0