专题训练之莫比乌斯反演入门级别

https://cn.vjudge.net/contest/304964 密码123123

A Visible Lattice Points

这次专题有六个,只会四个,我好菜呀!555....

Consider a N*N*N lattice. One corner is at (0,0,0) and the opposite one is at (N,N,N). How many lattice points are visible from corner at (0,0,0) ? A point X is visible from point Y iff no other lattice point lies on the segment joining X and Y. 
 
Input : 
The first line contains the number of test cases T. The next T lines contain an interger N 
 
Output : 
Output T lines, one corresponding to each test case. 
 
Sample Input : 




 
Sample Output : 

19 
175 
 
Constraints : 
T <= 50 
1 <= N <= 1000000

问能从,1,1,1看出去,不被阻挡的(x,y,z)的个数,其实就是gcd(x,y,z)=1,但是wa了很多发,百度题解

来自:https://blog.csdn.net/codeswarrior/article/details/81876769

看来没想象中的简单

#include
using namespace std;
typedef long long ll;
const ll mod=1000000007;
const int N=1e6+10;
const int maxn=1e6+5;
int isPrime[N];
int miu[N];
int prime[N];
int num_prime;
void getmiu(){
    memset(isPrime,0,sizeof(isPrime));
    miu[1]=1;
    for(ll i=2;i<=maxn;i++){
        if(isPrime[i]==0) prime[num_prime++]=i,miu[i]=-1;
        for(ll j=0;jmaxn) break;
            isPrime[i*prime[j]]=1;
            if(i%prime[j]==0){
                miu[i*prime[j]]=0;
                break;
            }else miu[i*prime[j]]=-1*miu[i];
        }
    }
}
 
int main()
{
    getmiu();
    int t;
    scanf("%d",&t);
    while(t--)
    {
    	ll n;
	    scanf("%lld",&n);
	    ll ans=0;
	    for(ll i=1;i<=n;i++)
	    {
	    	ans=(ans+miu[i]*(n/i)*(n/i)*(n/i+3));
            //(n / i) * (n / i) * 3 相当于在面上的和
            //(n / i) * (n / i) *(n / i)相当于一般情况
		}
		printf("%lld\n",ans+3);
	}
    
}

B - GCD

 

Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you're only required to output the total number of different number pairs. 
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same. 

Yoiu can assume that a = c = 1 in all test cases. 

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases. 
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above. 

Output

For each test case, print the number of choices. Use the format in the example. 

Sample Input

2
1 3 1 5 1
1 11014 1 14409 9

Sample Output

Case 1: 9
Case 2: 736427


        
  

Hint

For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).

这个题之前做过,莫比乌斯的经典题

需要注意的(1,4)和(4,1)是属于同一类,所以要统计一下b和d中 最小的一个,然后统计一遍sum就是包含两两重复的,ans减去1/2sum即可

#include
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a,b,c,d,k,t;
const int maxn=1e6+10;
int tot=0;
ll miu[maxn],prime[maxn];
bool isPrime[maxn];
void getmiu(){
	memset(isPrime,1,sizeof(isPrime));
    miu[1]=1;
    for(ll i=2;i<=maxn;i++){
        if(isPrime[i]) prime[++tot]=i,miu[i]=-1;
        for(ll j=1;j<=tot;j++){
            if(i*prime[j]>maxn) break;
            isPrime[i*prime[j]]=false;
            if(i%prime[j]==0){
                miu[i*prime[j]]=0;//????
                break;
            }else miu[i*prime[j]]=-1*miu[i];
        }
    }
}
int main()
{
	getmiu();
	cin>>t;
	int cas=0;
	while(t--)
	{
		cin>>a>>b>>c>>d>>k;
		if(k==0)
		{
			printf("Case %d: 0\n",++cas);
			continue;
		}
		//b/=k;d/=k;
		ll up=min(b,d);
		ll ans=0,a1=0,a2=0;
		for(ll i=k;i<=up;i+=k)
		{
			a1=a1+miu[i/k]*(b/i)*(d/i);
			a2=a2+miu[i/k]*(up/i)*(up/i);
		}
		ans=a1-a2/2;
		printf("Case %d: %lld\n",++cas,ans);
	}
}

E - Gcd

 

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.

 

Input

一个整数N

Output

如题

Sample Input

4

Sample Output

4

Hint

 

hint

对于样例(2,2),(2,4),(3,3),(4,2)

 

1<=N<=10^7

简单的水题,枚举素数,套用反演后的公式即可。

这题听说还有种容斥的解法,我不太会,我直接用的莫比乌斯,最简单的莫比乌斯用法

#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1e7+30,M=1e7+30;
int n;
int isPrime[N];
int miu[N];
int prime[M];
int num_prime;
void getmiu(int maxn){
    miu[1]=1;
    for(ll i=2;i<=maxn;i++){
        if(isPrime[i]==0) prime[num_prime++]=i,miu[i]=-1;
        for(ll j=0;jmaxn) break;
            isPrime[i*prime[j]]=1;
            if(i%prime[j]==0){
                miu[i*prime[j]]=0;
                break;
            }else miu[i*prime[j]]=-1*miu[i];
        }
    }
}
int main()
{
	
	cin>>n;
	getmiu(n+10);
	ll ans=0;
	for(int i=0;i

F - 能量采集

栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量。在这些植物采集能量后,

栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起。 栋栋的植物种得非常整齐,一共有n列,每列

有m棵,植物的横竖间距都一样,因此对于每一棵植物,栋栋可以用一个坐标(x, y)来表示,其中x的范围是1至n,

表示是在第x列,y的范围是1至m,表示是在第x列的第y棵。 由于能量汇集机器较大,不便移动,栋栋将它放在了

一个角上,坐标正好是(0, 0)。 能量汇集机器在汇集的过程中有一定的能量损失。如果一棵植物与能量汇集机器

连接而成的线段上有k棵植物,则能量的损失为2k + 1。例如,当能量汇集机器收集坐标为(2, 4)的植物时,由于

连接线段上存在一棵植物(1, 2),会产生3的能量损失。注意,如果一棵植物与能量汇集机器连接的线段上没有植

物,则能量损失为1。现在要计算总的能量损失。 下面给出了一个能量采集的例子,其中n = 5,m = 4,一共有20

棵植物,在每棵植物上标明了能量汇集机器收集它的能量时产生的能量损失。 在这个例子中,总共产生了36的能

量损失。

Input

仅包含一行,为两个整数n和m。

Output

仅包含一个整数,表示总共产生的能量损失。

Sample Input

【样例输入1】 5 4 【样例输入2】 3 4

Sample Output

【样例输出1】 36 【样例输出2】 20 对于100%的数据:1 ≤ n, m ≤ 100,000。

 

这题跟第一题很类似,答案就是求2*(d-1)singema(1,n)singema(1,m)gcd(i,j)==d,莫比乌斯反演一下即可

#include
using namespace std;
typedef long long ll;
const int N=1e5+10,M=1e5+5;
int miu[N],prime[N],num_prime;
bool isPrime[N];
int n,m;
void getmiu()
{
	miu[1]=1;
	for(int i=2;i<=M;++i)
	{
		if(isPrime[i]==0) prime[num_prime++]=i,miu[i]=-1;
		for(int j=0;j>n>>m;
	int k=min(n,m);
	ll ans=0;
	for(int i=1;i<=k;++i)
	{
		for(int j=i;j<=k;j+=i)
		{
			ans=(ans+1ll*(2*(i-1)+1)*miu[j/i]*(n/j)*(m/j));
		}
	}
	printf("%lld\n",ans);
}

 

你可能感兴趣的:(数论---莫比乌斯反演)