bzoj2694 Lcm(反演)
阿新 • • 發佈:2019-01-26
Description
對於任意的>1的n gcd(a, b)不是n^2的倍數
也就是說gcd(a, b)沒有一個因子的次數>=2
Input
一個正整數T表示資料組數
接下來T行 每行兩個正整數 表示N、M
Output
T行 每行一個整數 表示第i組資料的結果
Sample Input
4
2 4
3 3
6 5
8 3
Sample Output
24
28
233
178
HINT
T <= 10000
N, M<=4000000
分析:
要求gcd(a,b)不能含平方因子,所以gcd(a,b)一定是mu不等於0的數
那麼我們設所有滿足條件的數為p
如果我們列舉這個p,則可以得到式子:
實際上這個式子和LCM之和的化簡方式大同小異(只是最開始的列舉元素不同而已)
式子中有一個列舉p的愚蠢操作
我們肯定不能無腦列舉啊,所以考慮進一步優化:
所以我們只要預處理出:
就可以解決該問題了
一開始我在想能不能線性篩,
但是不要忘了最開始我們的假設:
p是mu值不等於0的數
所以我們直接列舉mu不等於0的數,用它更新它的倍數,這樣的時間複雜度均攤應該是不超過O(nlogn)
tip
這道題的模數非常特殊,是2的整數次冪,
所以我們直接用int自然溢位,最後取模即可
最後的取%:
ans=(ans%p+p)%p;
(一開始少些了一個+p,就WA掉了,感覺很鬼)
//這裡寫程式碼片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=4000005;
const int p=1<<30;
int n,m,sshu[N],tot=0,mu[N],d[N];
bool no[N];
void make()
{
mu[1]=1;
for (int i=2;i<N;i++)
{
if (!no[i])
{
sshu[++tot]=i;
mu[i]=-1;
}
for (int j=1;j<=tot&&sshu[j]*i<N;j++)
{
no[sshu[j]*i]=1;
if (i%sshu[j]==0)
{
mu[i*sshu[j]]=0;
break;
}
mu[i*sshu[j]]=-mu[i];
}
}
for (int i=1;i<N;i++)
if (mu[i]!=0)
for (int j=i;j<N;j+=i)
d[j]=d[j]+i*(j/i)*(j/i)*mu[j/i];
for (int i=2;i<N;i++) d[i]+=d[i-1]; //字首和
}
int sum(int n)
{
return n*(n+1)/2;
}
int main()
{
make();
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
int last;
int ans=0;
for (int i=1;i<=min(n,m);i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans=ans+sum(n/i)*sum(m/i)*(d[last]-d[i-1]);
}
ans=(ans%p+p)%p;
printf("%d\n",ans);
}
return 0;
}