【51nod1847】奇怪的數學題


Portal -->51nod1847奇怪的數學題

Solution

  這個的話。。看到跟\(gcd\)相關這種東西。。那肯定是要先反演一波啦

  \(sgcd(i,j)\)這個東西看起來很麻煩不過其實就是\(gcd(i,j)\)的次大約數

  為了方便表示我們用\(f(x)\)表示\(x\)的次大約數,那么原來的式子可以寫成:

\[\begin{aligned} \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}sgcd(i,j)^k&=\sum\limits_{i=1}^n\sum\limits_{j=1}^{n}f(gcd(i,j))^k\\ &=\sum\limits_{d=1}^{n}f(d)^k\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(i,j)=d]\\ &=\sum\limits_{d=1}^{n}f(d)^k\sum\limits_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor \frac{n}{d}\rfloor}[gcd(i,j)=1]\\ &=\sum\limits_{d=1}^{n}f(d)^k\cdot(2\sum\limits_{i=1}^{\lfloor \frac{n}{d}\rfloor}\varphi(i)-1) \end{aligned} \]

  然后倒數第二部到最后一步是直接由\(\phi\)的定義得到的嗯(然后我就特別弱智地用\(\mu\)推了好久還要推錯了。。)

  然后現在我們就是要求出:

\[\sum\limits_{d=1}^{n}f(d)^k\cdot(2\sum\limits_{i=1}^{\lfloor \frac{n}{d}\rfloor}\varphi(i)-1) \]

  這個東西

  后半部分的話是經典的杜教篩求歐拉函數前綴和,然后因為\(i\)的上界是\(\lfloor \frac{n}{d}\rfloor\)所以求出前綴和以后分塊搞一波就好了

  關於杜教篩求歐拉函數前綴和。。具體一點的話。。。戳這里好了

​   

  然后前半部分的求法十分神仙(瘋狂%%%),為了防止變量名稱弄混,統一一下接下來的部分題目中給出的指數為\(K\),而用來枚舉的變量為\(k\)

  首先定義

\[G_i=\sum\limits_{j=2}^{i}f(j)^K \]

  然后我們令min_25中的那個\(g\)數組按照如下的定義計算:

\[\begin{aligned} &s(x)=x^K\\ &g_{i,j}=\sum\limits_{k=1}^{i}[k\in Prime或minp(k)>P_j]s(k) \end{aligned} \]

  然后我們思考一下在計算過程中,\(g_{i,j}=g_{i,j-1}-s(P_j)\cdot(g_{\lfloor\frac{i}{P_j}\rfloor,j-1}-g_{P_j-1,j-1})\)這一步中,括號中的那一部分的含義
  其實就是\(\sum\limits_{x}s(x)[minp(x)=P_j且minp(\frac{x}{P_j})>=P_j]\),然后這個其實就是這堆滿足條件的\(x\)\(f(x)^k\)之和

  然后又因為min_25篩中,每個數只會被考慮一次,所以我們直接多開一個數組把這堆東西加起來就好了

  但是這並沒有算上\(k\in Prime\)的情況,所以此外我們還要單獨算一下素數情況下的取值,其實也就是素數的個數(因為\(f(prime)=1\)),這個也是直接用min_25篩一下就好了

  

  最后還剩下一個小問題,\(g_{i,0}\)在初始化的時候要快速求出\(\sum\limits_{j=1}^{i}j^k\)

  注意到\(k\)很小,那么我們用第二類斯特林數處理一下:

\[\begin{aligned} \sum\limits_{i=1}^{n}i^K&=\sum_{i=1}^n\sum_{j=1}^K\begin{Bmatrix}K\\j\end{Bmatrix}i^\underline{j}\\ &=\sum_{j=1}^K\begin{Bmatrix}K\\j\end{Bmatrix}\sum_{i=1}^ni^\underline{j}\\ &=\sum_{j=1}^K\begin{Bmatrix}K\\j\end{Bmatrix}\frac{{(n+1)}^\underline{j+1}}{j+1} \end{aligned} \]

  然后就很愉快滴解決啦

  

  一些實現的細節(你別說個人感覺因為那個模數不是很友善所以寫起來有點麻煩。。)

1、取模的話可以自然溢出,\(unsigned\ int\)了解一下ovo

2、求下降階乘冪的時候,因為這題的模數不是質數,所以不能快樂求逆元,但是因為\(k\)比較小所以直接暴力一波,一個一個數乘,這堆數中必定有一個是\(j+1\)的倍數,所以可以直接先除再乘就好了,注意判斷的時候每次都取模判斷的話會愉快T掉,所以應該在一開始的時候先把余數算出來,然后根據余數的加法定理直接判就好了

  

  代碼的話大概長這個樣子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define ll long long
#define ui unsigned int
using namespace std;
const int MAXN=1e5+10;
map<ll,ui>Rec;
ui P[MAXN],loc1[MAXN],loc2[MAXN];
ui g[MAXN*2],rec[MAXN*2],sphi[MAXN],pcnt[MAXN*2],pw[MAXN*2],G[MAXN*2];
ui S[60][60];
bool vis[MAXN];
ll n,m,K,cnt,cntval,sq;
ui ans;
void prework(int n);
void init_loc(ll n);
void get_g();
int Pos(ll x){return x<=sq?loc1[x]:loc2[n/x];} 
ui Sum(ui l,ui r);
ui SumPhi(ll n);
ui calc_sumk(ll n);
ui ksm(ui x,ll y);
ui f(ll x){return G[Pos(x)]+pcnt[Pos(x)];}

int main(){
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	scanf("%lld%lld\n",&n,&K);
	prework(MAXN);
	sq=sqrt(n);
	m=upper_bound(P+1,P+1+cnt,sq)-P-1;
	init_loc(n);
	get_g();
	ans=0;
	ui pre=0,now;
	for (ll i=2,pos;i<=n;i=pos+1){
		pos=n/(n/i);
		now=f(i);
		ans+=(SumPhi(n/i)*2-1)*(now-pre);
		pre=now;
	}
	printf("%lu\n",ans);
}

ui ksm(ui x,ll y){
	ui ret=1,base=x;
	for (;y;y>>=1,base=base*base)
		if (y&1) ret=ret*base;
	return ret;
}

void prework(int n){
	cnt=0;
	sphi[1]=1;
	for (int i=2;i<=n;++i){
		if (!vis[i])
			P[++cnt]=i,sphi[i]=i-1;
		for (int j=1;j<=cnt&&P[j]*i<=n;++j){
			vis[i*P[j]]=true;
			if (i%P[j]==0){
				sphi[i*P[j]]=sphi[i]*P[j];
				break;
			}
			else
				sphi[i*P[j]]=sphi[i]*sphi[P[j]];
		}
	}
	for (int i=1;i<=n;++i) sphi[i]=sphi[i-1]+sphi[i];
	S[0][0]=1;
	for (int i=1;i<=K;++i){
		S[i][1]=1;
		for (int j=2;j<=i;++j)
			S[i][j]=S[i-1][j]*(ui)j+S[i-1][j-1];
	}
	for (int i=1;i<=cnt;++i) pw[i]=ksm(P[i],K);
}

void init_loc(ll n){
	cntval=0;
	for (ll i=1,pos;i<=n;i=pos+1){
		rec[++cntval]=n/i;
		pos=n/(n/i);
	}
	reverse(rec+1,rec+1+cntval);
	for (int i=1;i<=cntval;++i)
		if (rec[i]<=sq) loc1[rec[i]]=i;
		else loc2[n/rec[i]]=i;
}

ui Sum(ui l,ui r){
	ui tmp1=l+r,tmp2=r-l+1;
	if (tmp1%2==0) tmp1/=2;
	else tmp2/=2;
	return tmp1*tmp2;
}

ui SumPhi(ll n){
	if (n<MAXN) return sphi[n];
	map<ll,ui>::iterator tmp=Rec.find(n);
	if (tmp!=Rec.end()) return tmp->second;
	ui ret=Sum(1,n);
	for (ll i=2,pos;i<=n;i=pos+1){
		pos=n/(n/i);
		ret-=SumPhi(n/i)*(pos-i+1);
	}
	Rec[n]=ret;
	return ret;
}

ui calc_sumk(ll n){
	ui ret=0,tmpval;
	int tmp;
	for (int i=1;i<=K;++i){
		tmpval=1;
		tmp=(n-i+1)%(i+1);
		for (ll j=n-i+1;j<=n+1;++j,++tmp){
			if (tmp>=i+1) tmp-=i+1;
			if (!tmp) tmpval*=(ui)j/(i+1);
			else tmpval*=(ui)j;
		}
		ret+=S[K][i]*tmpval;
	}
	return ret;
}

void get_g(){
	for (int i=2;i<=cntval;++i) g[i]=calc_sumk(rec[i])-1,pcnt[i]=rec[i]-1,G[i]=0;
	for (int j=1;j<=m;++j){
		for (int i=cntval;i>=1&&rec[i]>=1LL*P[j]*P[j];--i){
			g[i]-=pw[j]*(g[Pos(rec[i]/P[j])]-g[Pos(P[j]-1)]);
			pcnt[i]-=pcnt[Pos(rec[i]/P[j])]-pcnt[Pos(P[j]-1)];
			G[i]+=g[Pos(rec[i]/P[j])]-g[Pos(P[j]-1)];
		}
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM