首先贴出代码(闭区间[1,n]范围内和m互质的数)
代码:
int solve(II n,II m){ vectorp; for(II i=2;i*i<=m;i++){ if(m%i==0){ p.push_back(i); while(m%i==0) m/=i; } } if(m>1) p.push_back(m); II sz=p.size(); LL sum=0; for(II i=1;i<(1< ){ II ct=0; LL mul=1; for(II j=0;j ){ if(i&(1<<j)){ ct++; mul*=p[j]; } } if(ct&1) sum+=n/mul; else sum-=n/mul; } return n-sum; }
这里解释一下原理:首先假设m有x个不同的质因子,那么可以组成的因子数就是2^x-1种,然后10^18以内所有的数的质因子个数不会超过15个,所以2^15次方暴力枚举所有情况这个复杂度还是可取的。我们假设p1,p2,p3都是m的质因子,假设当前枚举的因子是p1*p2*p3那么n以内可以整除p1*p2*p3的数量就是n/(p1*p2*p3),但是这里考虑到一个会重复问题就是拥有奇数个质因数的因子的在n以内可以整除的数量已经包含了偶数个数量,但是偶数个的并不包含奇数个的,所以我们枚举的时候需要奇加偶减,这样我们算出来的ans是n以内和m不互质的数的数量,那么和m互质的数量就是n-ans。
贴上一些可以用这个方法解决的练习题:
HDU1695:这个题好像正解使用什么莫比乌斯反演,题目的意思是求[1,a],[1,b]有多少对数GCD(x,y)==k,但是(x,y)和(y,x)算一对,有一个定理如果GCD(x,y)==k ,则GCD(x/k,y/k)==1那么现在问题转化为求[1,a/k],[1,b/k]以内互质的数有多少对,现在我们要取minn=min(a/k,b/k),我们可以先求minn的欧拉函数的前缀和,然后再求minn+1到max(a/k,b/k)的数在[1,max(a/k.b/k)]以内所有与它互质的数的数量,然后把所有的加起来就可以了。
代码:
1 //Author: xiaowuga 2 #include3 using namespace std; 4 #define inf 0x3f3f3f3f 5 #define MAX INT_MAX 6 #define mem(s,ch) memset(s,ch,sizeof(s)) 7 const long long N=100000; 8 const long long mod=1e9+7; 9 typedef long long LL; 10 typedef int II; 11 typedef unsigned long long ull; 12 #define nc cout<<"nc"< 13 #define endl "\n" 14 vector Euler; 15 void init_Euler(II n){ 16 Euler.resize(n+1); 17 Euler[0]=0; 18 Euler[1]=1; 19 for(LL i=2;i i; 20 for(LL i=2;i ){ 21 if(Euler[i]==i){ 22 for(LL j=i;j i) 23 Euler[j]=Euler[j]/i*(i-1);//先进行除法防止溢出 24 } 25 } 26 for(II i=1;i ){ 27 Euler[i]+=Euler[i-1]; 28 } 29 } 30 int solve(II n,II m){ 31 vector p; 32 for(II i=2;i*i<=m;i++){ 33 if(m%i==0){ 34 p.push_back(i); 35 while(m%i==0) m/=i; 36 } 37 } 38 if(m>1) p.push_back(m); 39 II sz=p.size(); 40 LL sum=0; 41 for(II i=1;i<(1< ){ 42 II ct=0; 43 LL mul=1; 44 for(II j=0;j ){ 45 if(i&(1<<j)){ 46 ct++; 47 mul*=p[j]; 48 } 49 } 50 if(ct&1) sum+=n/mul; 51 else sum-=n/mul; 52 } 53 return n-sum; 54 } 55 int main() { 56 ios::sync_with_stdio(false);cin.tie(0); 57 II a,b,c,d,k; 58 II T,ca=0; 59 init_Euler(100000+1000); 60 cin>>T; 61 while(T--){ 62 cin>>a>>b>>c>>d>>k; 63 if(k==0||k>b||k>d){ 64 cout<<"Case "<<++ca<<": "<<0<<endl; 65 continue; 66 } 67 if(b>d) swap(b,d); 68 b/=k;d/=k; 69 LL ans=Euler[b]; 70 for(II i=b+1;i<=d;i++){ 71 ans+=solve(b,i); 72 } 73 cout<<"Case "<<++ca<<": "< endl; 74 } 75 return 0; 76 }
POJ2773:这个题求第n个与k互质的数。
1.一个简单的思路就是如果[1,k]中有x个与k互质的数,那么[k+1,2*k]中也有x个,每个k个一个循环都会出现x个数与k互质,而且加入y 2.二分+验证的思想,首先一个数越大,那么他包含的与k互质的数一定越多对吧?这个性质不就是单调性吗?任何满足单调性的问题我们都可以用二分来解决,所以我们可以用二分,加验证的思想找到和第n个k互质的数是多少 代码: 1 //Author: xiaowuga
2 #include