大致思路就是先求出n的质因数假设是a1-an,然后在1-a的区间里面查找至少能整除{a1,a2...an}中一个元素的数有多少个,对1-b也做相同的处理,而找出来的元素肯定是与n不互质的,那么把区间的长度减去元素的个数就是那个区间里面与n互质的数的个数了,然后1-b的减去1-(a-1)的就是答案了。
而在1-a的区间里面查找至少能整除{a1,a2...an}中一个元素的数有多少个,这里就要用到容斥原理了。
首先来看容斥原理
在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
就比如质因数有2,3 然后1-10里面能整除2的有2,4,6,8,10;能整除3的有3,6,9;把这个看作成集合A,集合B,|A∩B|=1,|A|=5,|B|=3,|A∪B|=|A|+|B|-|A∩B|;
将这个公式推广到n个集合
回到题目,考虑质因子{a1,a2,a3..an},那么在[1-r]有多少个数能整除ai,答案就是[r/ai],但是单纯的把答案加上去肯定是错的(有些数可能被好几个质因子整除),这个时候就用到容斥原理来解决。
假设有m个质因子,那么就有2^m-1种情况(lcm(...),中间填入数字,每个数字都有两种选择,填还是不填,但不能全部都不填对吧);
附上模板
int solve (ll n, ll r) { vector<ll> p; p.clear(); for (int i=2; i*i<=n; ++i) if (n % i == 0) { p.push_back (i); while (n % i == 0) n /= i; } if (n > 1) p.push_back (n); //分解质因数 ll sum = 0; ll cur; ll mult = 1; ll bits = 0; ll s=1<<p.size(); for (ll msk=1; msk<s; msk++) { mult = 1; bits = 0; for (int i=0; i<p.size(); ++i) if (msk & (1<<i)) { bits++; mult *= p[i]; } cur = r / mult; if (bits % 2 == 1) sum += cur; else sum -= cur; } //printf("%lld\n",sum); return r - sum;//1-r与n互质的数的个数 }