算术(HDU-6715)
生活随笔
收集整理的這篇文章主要介紹了
算术(HDU-6715)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Problem Description
?
定義一個函數?μ(x):如果?x?等于?k?個不同的質數的乘積,則?μ(x)=(?1)^k,否則(即?x?有大于 1 的平方因子)?μ(x)=0?
定義?lcm(a,b)?為?a,b?的最小公倍數,給定?n,m,你需要求:?
Input
第一行一個正整數 T(T≤10)?表示數據組數?
接下來?T?行,每行兩個正整數 n,m(1≤n,m≤106),表示一次詢問
Output
輸出 T 行,每行一個整數表示該組數據的答案
Examples
Input
2
2 4
5 5
Output
-2
-2
思路:
對于式子??進行化簡,有:
將 ij 拆分,有:
由于莫比烏斯函數是積性函數,那么有:
將 k 提出,有:
考慮莫比烏斯函數 u(x) 的性質,已知:u(x) 為積性函數,當? 時,有
即:
進行推廣:當??時,有:
那么對于 k 來說,當滿足:?時
有:
因此,有:
進行反演,有:
進行化簡,有:
?
設 t=dk,進一步化簡:
預處理??即可
Source Program
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define PI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long #define Pair pair<int,int> LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; } LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; } LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); } const double EPS = 1E-10; const int MOD = 20101009; const int N = 1000000+5; const int dx[] = {-1,1,0,0,-1,-1,1,1}; const int dy[] = {0,0,-1,1,-1,1,-1,1}; using namespace std;int mu[N]; int prime[N]; bool bprime[N]; int cnt; LL sum[N]; void getMu(int n){//線性篩求莫比烏斯函數cnt=0;mu[1]=1;//根據定義,μ(1)=1memset(bprime,false,sizeof(bprime));for(int i=2;i<=n;i++){//求2~n的莫比烏斯函數if(!bprime[i]){prime[++cnt]=i;//存儲質數mu[i]=-1;//i為質數時,μ(1)=-1}for(int j=1;j<=cnt&&i*prime[j]<=n;j++){//枚舉i之前的素數個數bprime[i*prime[j]]=true;//不是質數if(i%prime[j])//i不是prime[j]的整數倍時,i*prime[j]就不會包含相同質因子mu[i*prime[j]]=-mu[i];//mu[k]=mu[i]*mu[prime[j]],因為prime[j]是質數,mu值為-1else{mu[i*prime[j]]=0;break;//留到后面再篩}}}for(int i=1;i<=n;i++)for(int j=1;j<=n/i;j++)sum[i*j]+=mu[i]*mu[j]; } int main(){getMu(1000000);int t;scanf("%d",&t);while(t--){int n,m;scanf("%d%d",&n,&m);if(n>m)swap(n,m);LL res=0;for(int t=1;t<=n;t++){LL sum1=0,sum2=0;for(int i=1;i<=n/t;i++)sum1+=mu[i*t];for(int j=1;j<=m/t;j++)sum2+=mu[j*t];res+=sum1*sum2*sum[t];}printf("%lld\n",res);}return 0; }?
總結
以上是生活随笔為你收集整理的算术(HDU-6715)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用技巧 —— 离散化
- 下一篇: 理论基础 —— 线性表 —— 双向链表