1. 程式人生 > 實用技巧 >Sqoop案例-匯入:RDBMS到HDFS

Sqoop案例-匯入:RDBMS到HDFS

Link


首先我們要求的是這個柿子:

\(\displaystyle \sum_{i=1}^{n} \sum_{j=1}^{m} 2 \times gcd(i,j) - 1\)

\(2\)\(1\) 提出來,變成:

\(\displaystyle (2 \times \sum_{i=1}^{n} \sum_{j=1}^{m} gcd(i.j)) - n \times m\)

我們主要解決得是這個柿子:

\(\displaystyle \sum_{i=1}^{n}\sum_{j=1}^{m} gcd(i,j)\)

接下來就到了我們的頹柿子的時間啦。

先列舉一個 \(d\) ,變成

\(\displaystyle \sum_{d = 1}^{min(n,m)} d\sum_{i = 1}^{n} \sum_{j=1}^{m} [gcd(i,j) == d]\)

把後面的那兩個求和提一個 \(d\) 變成:

\(\displaystyle\sum_{d =1}^{min(n,m)} d \sum_{i=1}^{n\over d}\sum_{j=1}^{m\over d} [gcd(i,j) == 1]\)

然後,我們可以有莫比烏斯反演得到一個柿子:

\([gcd(i,j) == 1] = \displaystyle\sum_{d\mid i,d \mid j} \mu(d)\)

把這個柿子帶回去可得

\(\displaystyle\sum_{d=1}^{min(n,m)} d \sum_{i=1}^{n\over d}\sum_{j=1}^{m\over d} \sum_{p\mid i,p\mid j}\mu(p)\)

交換一下求和順序,先列舉 \(p\) 可得: (注意列舉\(p\) 的上限是 \(min(n,m) \over d\) ,交換一下求和順序,上限也要改變):

\(\displaystyle\sum_{d=1}^{min(n,m)}d \sum_{p=1}^{min({n\over d},{m\over d})}\mu(p) \sum_{i=1}^{n\over d} [p\mid i] \sum_{j=1}^{m\over d} [p\mid j]\)

因為 \(1- {n\over d}\) 中能被 \(p\) 整除的數有 \(n \over {dp}\) 個,所以後面的列舉 \(i\)\(j\)

的柿子可以改變一下,變成:

\(\displaystyle\sum_{d=1}^{min(n,m)}d\sum_{p=1}^{min({n\over d},{m\over d})}\mu(p) \sum_{i=1}^{n\over dp} \sum_{j=1}^{m\over dp}\)

也就是 :

\(\displaystyle \sum_{d=1}^{min(n,m)} d \sum_{p=1}^{min({n\over d},{m \over d})}\mu(p) \lfloor {n\over dp} \rfloor\lfloor{m \over dp}\rfloor\)

運用一個技巧 ,設 \(Q = d \times p\) ,則 \(p = {Q \over d}\),把所有的 \(p\) 都替換掉,改為列舉 \(Q\),變成:

\(\displaystyle\sum_{d=1}^{min(n,m)}d \sum_{Q=1}^{min(n,m)}\mu({Q\over d}) \lfloor {n \over Q}\rfloor\lfloor{m\over Q}\rfloor\)

至於為什麼第二個求和的上限為 \(min(n,m)\),因為 \(p \in{min({n\over d},{m\over d})}\)\(Q\) 的取值範圍要在 \(p\) 的基礎上乘個 \(d\) 變成 \(min(n,m)\)

交換一下列舉順序,先列舉一下 \(Q\) 變為

\(\displaystyle\sum_{Q=1}^{min(n,m)}\sum_{d\mid Q}^{min(n,m)} d \times \mu({Q \over d}) \lfloor {n \over Q}\rfloor \lfloor {m \over Q} \rfloor\)

因為 \(\mu\) 的定義域是整數所以 \(Q\over d\) 也需要是整數,也就是 \(Q\mid d\)

後面 可以看成是:

\(\displaystyle\sum_{Q=1}^{min(n,m)}\sum_{d \mid Q}^{min(n,m)}id(d) * \mu({Q\over d})\lfloor{n\over Q}\rfloor\lfloor{m\over Q}\rfloor\)

又因為 \(id * \mu = \phi\), 後面的可以寫成卷積的形式,變成:

\(\displaystyle\sum_{Q=1}^{min(n,m)} \phi(Q) \lfloor{n \over Q}\rfloor\lfloor{m \over Q}\rfloor\)

這個我們就可以做到 O(n) 的回答了。

先預處理出 \(\phi\) 函式的值,然後根據上面的柿子計算出答案就可以啦;

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int N = 1e5+10;
int n,m,ans,tot,phi[N],prime[N];
bool check[N];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void YYCH()//預處理出φ函式的值
{
	phi[1] = 1;
	for(int i = 2; i <= N-5; i++)
	{
		if(!check[i])
		{
			prime[++tot] = i;
			phi[i] = i-1;
		}
		for(int j = 1; j <= tot && i * prime[j] <= N-5; j++)
		{
			check[i * prime[j]] = 1;
			if(i % prime[j] == 0)
			{
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			else
			{
				phi[i * prime[j]] = phi[i] * phi[prime[j]];
			}
		}
	}
}
int calc(int d)
{
	return (n/d) * (m/d);
}
signed main()
{
	n = read(); m = read();
	if(n > m) swap(n,m); YYCH();
	for(int i = 1; i <= n; i++)
	{
		ans += phi[i] * calc(i);//計算答案
	}
	ans = ans * 2 - n * m;
	printf("%lld\n",ans);
	return 0;
}

Update: 總算寫完了這一大堆柿子,累死我了