题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的。(b,d,k<=100000)
解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数。假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数。解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数。
在
for(int j=rem;j<=factor[i][0];j++) ans+=tool/factor[i][j]-getnum(i,tool/factor[i][j],j+1);这个循环中,ans加的等号后每项表示当前最大的质因子是factor[i][j]的数量,目的是去重。
解法2:莫比乌斯,莫比乌斯数组确实很有用。其实也很简单,mou的位置的含义是,首先如果i有个质因子出现2次或以上,则mou值为0,否则1与-1跟i的质因子奇偶性决定。目的也是容斥。
解法1代码:
/****************************************************** * @author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 #define zero(_) (abs(_)<=eps) const double pi=acos(-1.0); typedef long long LL; const int Max=100010; const LL INF=0x3FFFFFFF; int a, b, c, d, k; int factor[Max][20]; bool rem[Max]; LL oular[Max]; void init() { for(int i=1; i<Max; i++) oular[i]=i; for(LL i=2; i<Max; i++) { if(!rem[i]) { factor[i][++factor[i][0]]=i; oular[i]=i-1; for(LL j=i*2; j<Max; j+=i) { factor[j][++factor[j][0]]=i; rem[j]=1; oular[j]=oular[j]*(i-1)/i; } } } for(int i=1; i<Max; i++) oular[i]=oular[i]+oular[i-1]; } LL getnum(int i,int tool,int rem) { int ans=0; for(int j=rem;j<=factor[i][0];j++) ans+=tool/factor[i][j]-getnum(i,tool/factor[i][j],j+1); return ans; } int main() { int t; cin>>t; init();int kk=1; while(t--) { cin>>a>>b>>c>>d>>k; printf("Case %d: ",kk++); if(k==0) { cout<<"0\n"; continue; } b/=k; d/=k; if(b>d)swap(b,d); LL ans=oular[b]; for(int i=b+1;i<=d;i++) { ans+=b-getnum(i,b,1); } cout<<ans<<endl; } return 0; }解法2代码:
/****************************************************** * @author:xiefubao *******************************************************/ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <vector> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <string.h> //freopen ("in.txt" , "r" , stdin); using namespace std; #define eps 1e-8 #define zero(_) (abs(_)<=eps) const double pi=acos(-1.0); typedef long long LL; const int Max=100010; const LL INF=0x3FFFFFFF; int a, b, c, d, k; bool rem[Max]; int mou[Max]; void init() { mou[1]=1; for(LL i=2; i<Max; i++) { if(!rem[i]) { mou[i]=i; for(LL j=i*2; j<Max; j+=i) { rem[j]=1; mou[j]=i; } } } for(int i=2; i<Max; i++) { if(i/mou[i]%mou[i]==0) mou[i]=0; else mou[i]=-mou[i/mou[i]]; } } int main() { int t; cin>>t; init(); int kk=1; while(t--) { cin>>a>>b>>c>>d>>k; printf("Case %d: ",kk++); if(k==0) { cout<<"0\n"; continue; } b/=k; d/=k; if(b > d)swap(b,d); long long ans1 = 0; for(int i = 1; i <= b; i++) ans1 += (long long)mou[i]*(b/i)*(d/i); long long ans2 = 0; for(int i = 1; i <= b; i++) ans2 += (long long)mou[i]*(b/i)*(b/i); ans1 -= ans2/2; cout<<ans1<<endl; } return 0; }
原文:http://blog.csdn.net/xiefubao/article/details/41178611