Gcd表中的质数 51Nod - 1192 (莫比乌斯反演)
2017-10-21 01:48
531 查看
有一个M * N的表格,行与列分别是1 - M和1 - N,格子中间写着行与列的最大公约数Gcd(i, j)(1 <= i <= M, 1 <= j <= N)。
例如:M = 5, n = 4。
1 2 3 4 5
1 1 1 1 1 1
2 1 2 1 2 1
3 1 1 3 1 1
4 1 2 1 4 1
给出M和N,求这张表中有多少个质数。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000)
第2 - T + 1行:每行2个数M,N,中间用空格分隔,表示表格的宽和高。(1 <= M, N <= 5 * 10^6)
Output
共T行,每行1个数,表示表格中质数的数量。
Sample Input
2
10 10
100 100
Sample Output
30
2791
莫比乌斯的经典哦
设F(n)为gcd(x,y)是n的倍数的数量,易知F(x)=nx∗mx
设f(n)为gcd(x,y)为n的数量,则:
F(n)=∑n|df(d)
所以反演得:f(n)=∑n|dμ(dn)F(d)
所以:ans=∑p为素数min(n,m)∑p|dμ(dp)F(d)
转换枚举变量(固定套路):ans=∑d=1min(n,m)F(d)∑p|dp为素数μ(dp)
设sum(x)=∑p为素数p|dμ(dp),把sum这个数组预处理出来即可,但是超时了,那分块就好了,把sum处里成前缀和即可
例如:M = 5, n = 4。
1 2 3 4 5
1 1 1 1 1 1
2 1 2 1 2 1
3 1 1 3 1 1
4 1 2 1 4 1
给出M和N,求这张表中有多少个质数。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000)
第2 - T + 1行:每行2个数M,N,中间用空格分隔,表示表格的宽和高。(1 <= M, N <= 5 * 10^6)
Output
共T行,每行1个数,表示表格中质数的数量。
Sample Input
2
10 10
100 100
Sample Output
30
2791
莫比乌斯的经典哦
设F(n)为gcd(x,y)是n的倍数的数量,易知F(x)=nx∗mx
设f(n)为gcd(x,y)为n的数量,则:
F(n)=∑n|df(d)
所以反演得:f(n)=∑n|dμ(dn)F(d)
所以:ans=∑p为素数min(n,m)∑p|dμ(dp)F(d)
转换枚举变量(固定套路):ans=∑d=1min(n,m)F(d)∑p|dp为素数μ(dp)
设sum(x)=∑p为素数p|dμ(dp),把sum这个数组预处理出来即可,但是超时了,那分块就好了,把sum处里成前缀和即可
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #define N 5000005 using namespace std; typedef long long ll; vector<int> prime; bool pri ; int mu ; int sum ; int cal ; void init() { memset(pri,true,sizeof(pri)); mu[1]=1; for(int i=2;i<N;i++) { if(pri[i]) { prime.push_back(i); mu[i]=-1; } for(int j=0;j<prime.size()&&i*prime[j]<N;j++) { pri[i*prime[j]]=false; if(i%prime[j]) mu[i*prime[j]]=-mu[i]; else { mu[i*prime[j]]=0; break; } } } //cout<<sum[1]<<endl; for(int i=0;i<prime.size();i++) for(int j=prime[i];j<N;j+=prime[i]) sum[j]+=mu[j/prime[i]];//筛法筛出sum的值 for(int i=1;i<N;i++)//处理成前缀和 cal[i]=cal[i-1]+sum[i]; } int main() { int t; init(); int n,m; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); int limit=min(n,m); ll ans=0; int last; for(int i=1;i<=limit;i=last+1) { last=min(n/(n/i),m/(m/i)); ans+=(ll)(n/i)*(m/i)*(cal[last]-cal[i-1]);//分块 } /*for(int i=1;i<=limit;i++) ans+=(ll)(n/i)*(m/i)*sum[i];*///这种写法t了,才想着要分块 cout<<ans<<endl; } return 0; }
相关文章推荐
- 【51NOD 1192】Gcd表中的质数
- 51nod 1192 Gcd表中的质数
- 51nod 1192 Gcd表中的质数 莫比乌斯反演
- 51Nod-1192-Gcd表中的质数
- 51nod_1106 质数检测
- HDU 1695 GCD (莫比乌斯反演)
- HDU 1695 GCD(莫比乌斯反演)
- BZOJ 2820 YY的GCD 莫比乌斯反演
- 51nod 1106 质数检测(miller rabin 素数测试.)
- 【BZOJ2820】YY的GCD(莫比乌斯反演)
- HDU 1695 GCD (莫比乌斯反演)
- 51nod 1355 斐波那契的最小公倍数 (数论+莫比乌斯反演)
- HYSBZ 2818 (GCD)莫比乌斯反演
- 【bzoj2820】YY的GCD 莫比乌斯反演
- 【51nod】2026 Gcd and Lcm
- 51Nod-1106 质数检测
- 51Nod 1181: 质数中的质数(质数筛法)
- [BZOJ2820]YY的GCD(莫比乌斯反演)
- BZOJ 2820 YY的GCD(莫比乌斯反演)
- [51Nod 2026] Gcd and Lcm