题意:求解区间a~b与n互质数的个数
题解:转化为1~b与n互质数减去1~a与n互质数的个数,典型的容斥。(由于这里数据范围太大,莫比乌斯就不适用了,直接用容斥枚举质数的组合,负责都根号n)
补充:2017.8.18 多校的容斥没写出来,整理一下。一般容斥的思路,求解逆问题。这道题目的逆问题就是不与n互质的数。这里有一个点,我们判断两个数是否互素,只要看把这两个
数唯一分解之后有没有相同的素因子。
ac代码:
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; typedef long long ll; ll a,b,n; //ll num[100001],vis[100001]; vector<ll>flag; vector<ll>deg; ll prime[100001]; void deal() { int ret=0; flag.clear(); deg.clear(); for(int i=2;i*i<=n;i++)//得到n的素因子 { if(n%i==0) { prime[ret++]=i; while(n%i==0) n/=i; } } if(n>1) prime[ret++]=n;
for(int i=1;i<(1<<ret);i++) { ll cnt=0; ll temp=1; for(int j=0;j<ret;j++) { if(i&(1<<j)) { cnt++; temp*=prime[j]; } } // cout<<temp<<' '; flag.push_back(cnt); deg.push_back((b/temp)-((a-1)/temp));// 这个细节注意一下,区间的开闭,,错了好几次! } } int main() { int t,Case=0; scanf("%d",&t); while(t--) { scanf("%lld %lld %lld",&a,&b,&n); deal(); // cout<<endl; ll ans=0; int len=flag.size(); for(int i=0;i<len;i++) { //if(flag[i]==0) continue; if(deg[i] > b) break; if(flag[i]%2) ans+=deg[i]; else ans-=deg[i]; } ll zz=b-a+1; printf("Case #%d: %lld ",++Case,zz-ans); } return 0; }