HRY and mobius 19華工I--莫比烏斯函數性質與杜教篩

杜教篩模板鏈接

 

華工題目鏈接

 

萬惡之源--bzoj2440  完全平方數  應該是這道題前身。

進階版--【SPOJ】DIVCNT2

 

題意:  給n,k,   求\sum_{i=1}^{n}\mu^{k} (i)

一.核心

莫比烏斯函數平方及以上因子=0,無平方因子(即素因子次數最大爲1)=\pm 1,如果都當成1來算,他們前綴和不正是:

\sum_{i=1}^{n}\mu^{2} (i)等價於小於等於n,不含平方因子的個數和

 

二.化簡證明:

 

第一種:容斥

莫比烏斯函數本質爲容斥係數出發(不理解見鏈接)

求不含平方因子的個數和,容斥表達=1的平方的倍數的數(全部數)-2的平方的倍數的數-3的平方的倍數的數+6平方的的倍數的數(減2和3平方的倍數的時候減多了一部分,加回來)...數學上可以寫成是\sum_{d=1}^{\sqrt{n}} x*\frac{n}{d^{2}},x就是容斥係數,剛好就是莫比烏斯函數。

因此\sum\limits_{d=1}^{\sqrt n}\mu(d)\lfloor\frac{n}{d^2}\rfloor=n-\sum\limits_{d=2}^{\sqrt n}\mu(d)\lfloor\frac{n}{d^2}\rfloor

 

 

第二種:嚴謹證明

\sum\limits_{i=1}^{n}\mu^{2}(i)=\sum\limits_{i=1}^{n}\sum\limits_{d^2|i}\mu(d)=\sum\limits_{d=1}^{\sqrt n}\mu(d)\lfloor\frac{n}{d^2}\rfloor

①第一個等號怎麼來的?

②第二個等號:用d消去i,常見轉換

 

(可能可行?)猜想--第三種:狄利克雷卷積構造g(x)套杜教篩

好像狄利克雷卷積只能結合一次...所以下面寫法應該不對,先寫出來吧。

\mu *\mu =(\mu *id*I)*(\mu *id*I)= (\varphi *I)^{2}=id^{2}

g(x)=(id*I)^{2}=id^{2}

 

三.代碼

注意除了prime其他用long long

#include <bits/stdc++.h>
//#include<tr1/unordered_map>
using namespace std;
//using namespace std::tr1;//頭文件和std都要加,c++11可用
 
typedef long long ll;
typedef unsigned long long ull;
const int N = 5e6+5;

 
ll mu[N],phi[N],mu2[N];//mu用來存前綴和
int prime[N];
int vis[N];
map<ll,ll>ansmu,ansphi,ansmu2;//數組不夠大,額外開,需要map
//unorder_map比普通map少了排序,會快一些 
 
inline int read() {   //輸入掛
    ll X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}
 
void init()
{
	int cnt=0;
	mu[1]=mu2[1]=1;
	for(int i=2;i<=N;i++)//統一ll和int!!!
	{
		if(!vis[i])    
		{
			prime[++cnt]=i;//++寫在前面 
			mu[i]=-1;//素數  只有它本身一個素因子
			mu2[i]=-1;
		} 
		for(int j=1;prime[j]*i<=N&&j<=cnt;j++)//不越兩界 
		{
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				//mu[i*prime[j]]=0;//初始化爲0所以這項可有可無 
					break;
			}
			
				else
				{
					
					mu[i*prime[j]]=-mu[i];//多一個素因子變正負  
					mu2[i*prime[j]]=-mu2[i];
				}
				   
		}
	}
	for(int i=1;i<=N;i++)mu[i]+=mu[i-1];//前綴和 
}

ll S_mu(ll n)
{
	if(n<N)return mu[n];//同上
	if(ansmu[n])return ansmu[n];
	ll ans=1;
	for(ll l=2,r;l<=n;l=r+1)
	   r=n/(n/l) ,ans-=(r-l+1)*S_mu(n/l);  //I*mu
	return ansmu[n]=ans;
}

ll S_mu2(ll n)
{

		ll t=sqrt(n);
		ll ans=0;
		for(ll i=1;i<=t;i++){
			if(n/(i*i)==0)break;//不剪枝也不會TLE 
			ans+=mu2[i]*(n/(i*i));
		}
		return ans;
	
}
 
 
int main()
{
init();
int T=read();
ll n,k;

while(T--)
{
	//ll n=read();	ll k=read();//如果用輸入掛也要改ll
 
	scanf("%lld %lld",&n,&k);
	if(k==0)  printf("%lld\n",n);
	else if(k%2==1)printf("%lld\n",S_mu(n));
	else printf("%lld\n",S_mu2(n));
 } 
 return 0;
 
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章