1. 程式人生 > >南京理工大學第八屆程式設計大賽triple

南京理工大學第八屆程式設計大賽triple

題目連結:https://icpc.njust.edu.cn/Contest/749/D/

題目大意:在一定範圍內找出三個最大公約數為m且各不相同的數,問有多少中情況。

解題思路:剛開始的時侯用容斥寫,因為對於這個題而言質因子的分佈在1到10的5次方,所以就有大概9千多個質數,而我寫的容斥是n^2的,所以就超時,所以這題不能用質因子去容斥,而直接用n的因子,時間複雜度更低。所以n^2的容斥對某一個數的篩選表現更好,因為一個數的質因子很少。後來用莫比烏斯反演寫了一發,果然快多了。F(m)=n/m*(n/m-1)*(n/m-2)。

莫比烏斯反演:

/* ********************************
Author			: danmu
Created Time	: 2016年04月17日 星期日 23時28分00秒
File Name		: triple.cpp

Vim Command
copy -> yy
paste -> p P
del this line -> dd
Ctrl-Z -> u U
copy into system -> "+y
******************************** */

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <list>
#include <map>
#include <set>

#define ULL unsigned long long
#define PI 3.1415926535
#define INF 0x3f3f3f3f
#define LL long long
#define eps 1e-8
#define MAX 100000
using namespace std;
bool vis[MAX+10];  
int mu[MAX+10],prime[MAX+10],cnt;  
void mobi(int n){  
    memset(vis,false,sizeof(vis));  
    mu[1]=1;  
    cnt=0;  
    for(int i=2;i<=n;++i){  
        if(!vis[i]){  
            prime[cnt++]=i;  
            mu[i]=-1;  
        }  
        for(int j=0;j<cnt&&i*prime[j]<=n;++j){  
            vis[i*prime[j]]=1;  
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];  
            else{  
                mu[i*prime[j]]=0;  
                break;  
            }  
        }  
    }  
}  
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int t;
	mobi(100000);
	scanf("%d",&t);
	while(t--){
		int n,m;
		LL ans=0;
		scanf("%d%d",&n,&m);
		LL tmp=n/m;
		/*if(tmp<3){
			printf("0\n");
			continue;
		}*/
		for(int i=1;i<=tmp;++i)
			ans+=mu[i]*(tmp/i*(tmp/i-1)*(tmp/i-2)/6);
		printf("%lld\n",ans);
	}	
	return 0;
}