1. 程式人生 > >[loj6053]簡單的函式【min_25篩】

[loj6053]簡單的函式【min_25篩】

【題目連結】
  https://loj.ac/problem/6053
【題解】
  min_25篩的模板題。
  min_25篩可以解決以下一類積性函式的求和問題。
  1.f(x)(xP)f(x)(x \in P)可以通過多項式表達出來。
  2.f(xk)(xP)f(x^k)(x \in P)可以快速算出。
  這道題中,f(x)=xf(x) = x^1=x1(xPx2)1 = x - 1(x \in P 且x \neq 2)所以條件1滿足,條件2顯然也是滿足的。
  part1
  我們先來考慮一個問題,如何求F

(T)=i=1Tf(i)(iP,TN/i)F(T)=\sum_{i=1}^{T}f(i)(i\in P,T\in \left\lfloor N/i\right\rfloor ),T是N通過除法能得到的數,大約有2N2 \sqrt{N}種取值。
  不難發現,i=1Nf(i)(iP)=i=1Ni1(iP)+2\sum_{i=1}^{N}f(i)(i\in P) = \sum_{i=1}^{N}i-1(i\in P) + 2 因為只有2異或了後會加1。
   那麼我們要求的就是質數的和以及質數的個數。
   首先篩出1..
N1..\sqrt{N}
中的所有質數,記作p[1]..p[M]p[1]..p[M]
   記函式Gk(n,m)G_{k}(n, m)表示i=1nik(iPi>p[m])\sum_{i = 1}^{n}i^k(i \in P或i的最小質因子>p[m])
   那麼相當於求出G0(T,M),G1(T,M)G_{0}(T,M),G_{1}(T,M)
   考慮從Gk(n,m1)G_{k}(n,m-1)推到Gk(n,m)G_{k}(n,m),就是從中去除最小質因子是p[m]p[m]的,於是可以推出:
   Gk(n,m)=Gk(n,m1)p[m]k(Gk(n/p[m],m1)Gk(p[m]1,m1))G_{k}(n,m)=G_{k}(n,m-1)-p[m]^k*(G_{k}(\left\lfloor n/p[m]\right\rfloor,m-1)-G_{k}(p[m]-1,m-1))
   相當於強制選出一個p[m]p[m],剩下的隨便選,但要重新加上有比p[m]p[m]更小的質因子的方案。
   邊界條件是Gk(n,0)=i=1nikG_{k}(n,0)=\sum_{i=1}^{n}i^k,可以O(1)O(1)計算。
   由於我們只要求2N2\sqrt{N}個取值,可以將它們一起考慮。
   具體來說,我們從前往後列舉每一個質數p[1]..p[m]p[1]..p[m]由於大的的取值不會影響小的,所以從後往前更新。
   現在的複雜度是N(sqrtN/lnN)=O(N/lnN)\sqrt{N}*(sqrt{N}/ln{\sqrt{N}})=O(N/ln{\sqrt{N}})
   考慮優化,當p[m]2>np[m]^2>n時,Gk(n,m)=Gk(n,m1)G_{k}(n,m)=G_{k}(n,m-1),因為不可能存在一個有p[m]p[m]的因子但不是質數的數,所以每次有一段字首不用算。
   現在的複雜度是Ti=1m[p[i]2T]O(N3/4/lnN)\sum_{T}\sum_{i=1}^{m}[p[i]^2 \leq T]\approx O(N^{3/4}/ln{N})?,我不會證,但肯定比O(N3/4)O(N^{3/4})小。
   Part2
   處理出了FF接下來就簡單了。
   記S(n,m)S(n,m)i=1nf(i)[ip[m]]\sum_{i=1}^{n}f(i)[i的最小質因子\geq p[m]],我們要求的是S(N,1)+f(1)S(N,1)+f(1)
   由於我們已經知道了FF(質數的答案和)。現在要加入非質數的答案。還是考慮列舉質數:
   S(n,m)=F(n)F(p[m]1)+i=mMj=1p[i]j+1N(f(p[i]j)S(n/p[i]j,i+1)+f(p[i]j+1))S(n,m)=F(n)-F(p[m]-1)+\sum_{i=m}^{M}\sum_{j=1}^{p[i]^{j+1}\leq N}(f(p[i]^j)*S(n/p[i]^j,i+1)+f(p[i]^{j+1}))
   由於p[M]Np[M]\leq \sqrt{N}所以它的FF值也是已知的。
   邊界條件是n<p[m]n<p[m]時,值為0。
   這個相當於是把上一部分的遞迴實現,所以複雜度與Part1相同。
   總時間複雜度:O(N3/4/lnN)O(N^{3/4}/ln{N})一般能做到1e101e10
【程式碼】(為了便於除錯很多地方寫的比較煩)

/* - - - - - - - - - - - - - - -
	User : 		VanishD
	problem :	loj-6053
	Points : 	Min_25 
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define 	ll 		long long
# define 	inf 	0x3f3f3f3f
# define 	P 		1000000007
# define 	N 		1001000
using namespace std;
ll use[N], p[N], pre[N], bak[N], pre0[N], pre1[N], bak0[N], bak1[N];
ll sum, nt, cnt;
int pnum;
const ll inv2 = 5e8 + 4; 
void get_p(int n){
	use[1] = true; 
	for (int i = 2; i <= n; i++){
		if (!use[i]) p[++pnum] = i;
		for (ll j = 1; j <= pnum && 1ll * i * p[j] <= n; j++){
			use[i * p[j]] = true;
			if (i % p[j] == 0) break;
		}
	}
}
ll F(ll p, int k){
	if (k == 0) return 1;
	return p ^ k;
}
void get_Pow0(){
	for (int i = 1; i <= nt; i++)
		pre0[i] = i, bak0[i] = sum / i;
	for (int i = 1, prep = 1, bakp = nt; i <= pnum; i++){
		while (prep <= nt && p[i] * p[i] > prep) prep++;
		while (bakp >= 1  && p[i] * p[i] > sum / bakp) bakp--;
		for (int j = 1; j <= bakp; j++){
			ll x = sum / j;
			ll  tmp1 = (x <= nt) ? pre0[x] : bak0[sum / x],
				tmp2 = (x / p[i] <= nt) ? pre0[x / p[i]] : bak0[sum / (x / p[i])],
				tmp3 = pre0[p[i] - 1];
			bak0[j] = (tmp1 - 1 * (tmp2 - tmp3) + P) % P;
		}			
		for (int j = nt; j >= prep; j--){
			ll x = j;
			ll  tmp1 = (x <= nt) ? pre0[x] : bak0[sum / x],
				tmp2 = (x / p[i] <= nt) ? pre0[x / p[i]] : bak0[sum / (x / p[i])],
				tmp3 = pre0[p[i] - 1];
			pre0[j] = (tmp1 - 1 * (tmp2 - tmp3) + P) % P;
		}			
	}
	for (int i = 1; i <= nt; i++) pre0[i] -= 1, bak0[i] -= 1;
}
void get_Pow1(){
	for (int i = 1; i <= nt; i++){
		pre1[i] = 1ll * i * (i + 1) % P * inv2 % P;
		ll tmp = (sum / i) % P;
		bak1[i] = tmp * (tmp + 1) % P * inv2 % P;
	}
	for (int i = 1, prep = 1, bakp = nt; i <= pnum; i++){
		while (prep <= nt && p[i] * p[i] > prep) prep++;
		while (bakp >= 1  && p[i] * p[i] > sum / bakp) bakp--;
		for (int j = 1; j <= bakp; j++){
			ll x = sum / j;
			ll  tmp1 = (x <= nt) ? pre1[x] : bak1[sum / x],
				tmp2 = (x / p[i] <= nt) ? pre1[x / p[i]] : bak1[sum / (x / p[i])],
				tmp3 = pre1[p[i] - 1];
			bak1[j] = (tmp1 - p[i] * (tmp2 - tmp3) % P + P) % P;
		}			
		for (int j = nt; j >= prep; j--){
			ll x = j;
			ll  tmp1 = (x <= nt) ? pre1[x] : bak1[sum / x],
				tmp2 = (x / p[i] <= nt) ? pre1[x / p[i]] : bak1[sum / (x / p[i])],
				tmp3 = pre1[p[i] - 1];
			pre1[j] = (tmp1 - p[i] * (tmp2 - tmp3) % P + P) % P;
		}
	}
	for (int i = 1; i <= nt; i++) pre1[i] -= 1, bak1[i] -= 1;
}
ll get_s(ll n, int m){
	if (n <= 1 || n < p[m]) return 0;
	ll ans = ((n > nt) ? bak[sum / n] : pre[n]) - pre[p[m] - 1];
	for (int i = m; i <= pnum && n >= 1ll * p[i] * p[i]; i++)
		for (ll j = 1, k = p[i]; k * p[i] <= n; j++, k *= p[i])
			ans = (ans + F(p[i], j) * get_s(n / k, i + 1) + F(p[i], j + 1)) % P;
	return ans;
}
int main(){
	ll n;
	scanf("%lld", &n);
	sum = n; nt = sqrt(n);
	get_p(nt);
	get_Pow0(); get_Pow1(); 
	for (int i = 1; i <= nt; i++){
		if (i == 1) pre[i] = 0;
			else pre[i] = (pre1[i] - pre0[i] + 2 + P) % P;
		bak[i] = (bak1[i] - bak0[i] + 2 + P) % P;
	}
	p[pnum + 1] = nt + 1;
	printf("%lld\n", (get_s(n, 1) + 1) % P);
	return 0;
}

相關推薦

[loj6053]簡單函式min_25

【題目連結】   https://loj.ac/problem/6053 【題解】   min_25篩的模板題。   min_25篩可以解決以下一類積性函式的求和問題。   1.f(x)(x∈P)f(x)(x \in P)f(x)(x∈P)可以通過多項式表達出來

nssl1210-質數素數

正題 題目大意 求l∼rl\sim rl∼r這個區間素數或兩個素數的乘積的數個數 解題思路 在歐式篩的時候判斷j是不是素數,是就標記就行了。 code #pragma GCC optimize(2

POJ 2689 Prime Distance素數

The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number theoreticia

oracle中如何寫函式oracle技術

在oracle資料開發中函式是必不可少的。函式可以一般是可以完成某一功能而編寫的,他儲存在資料中執行也是在資料庫中,有明確的歸屬。比如:使用者A建立了一個函式,如果A不公開這個函式,那麼oracle中的其他使用者是不能看到該函式的,除非有DBA許可權的使用者的。 函式必須制定返回值,如果有沒有制定返回

JavaScript實現兩個小球碰撞簡單模型未完

var xPos,xpos1;// var timer,timer1; var xSpeed;//黑球移動速度 var interval=50;//間隔時間 var countNum,co

LOJ6053簡單的函數(min_25

ios can long ring -s In IV Go else 題面 LOJ 題解 戳這裏 #include<iostream> #include<cstdio> #include<cstdlib> #include<cstr

GDAL學習過濾器,簡單的空間分析,函式和模組

1.屬性過濾器 >>>import ogr,os >>>os.chdir('E:/data/GDAL/ospy_data3') >>>driver=ogr.GetDriverByName('ESRI Shapefile') >>&

LOJ.6053.簡單函式(Min_25)

題目連結 Min_25篩見這裡: \(Description\) 給定\(n\),求積性函式\(f(p^c)=p\oplus c\)的字首和。\(\oplus\)表示異或運算。 \(n\leq 10^{10}\)。 \(Solution\) 所求積性函式為\(f(p^c)=p\oplus c,\q

問題 : 函式素數的判斷 簡單 函式

題目描述 請編寫函式PrimeJudge,其功能是判斷一個整數num是否為素數,如果是素數,則返回1,否則返回0。 #include <stdio.h> //你需要提交的程式碼 int main() { int num; scanf("%d",&

問題 : 函式求字串的長度 簡單 函式

題目描述 編寫一個求字串長度的函式,其原型如下: int strlen(char str[]); 其中str[]表示待求長度的字串,返回值是str[]的長度。 注意:主函式已經給出,只需提交strlen()函式及必要的標頭檔案包含命令。 後置程式碼: int

BZOJ 4805 尤拉函式求和杜教

求尤拉函式的字首和,項數小於2e9。 以目前的視野來看待杜教篩的話,感覺就像是將一個線性的式子,進一步優化,然後通過記憶化搜尋來實現的一個過程。 S(n)=∑i=1nϕ(i)S(n)=∑i=

LOJ 6053 簡單函式 - Min_25

不知道為啥腦子一抽就來溫習了一波Min_25篩 這題F( p )=p-1(除了p=2,這個特判一下即可),最後把2加回來。 #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define

杜教51Nod1244[莫比烏斯函式之和]題解

題目概述 求 ∑ni=1μ(i) 。 解題報告 杜教篩可以用來求積性函式的字首和,具體想法是用另外一個函式卷待求函式,如下: ∑i=1n(f∗g)(i)=∑i=1n∑d|if(id)g(d)

簡單函式——Min_25

%%yyb %%zsy 就是實現一下Min-25篩 篩積性函式的操作 首先要得到 $G(M,j)=\sum_{t=j}^{cnt} \sum_{e=1}^{p_t^{e+1}<=M} [\phi(p_t^e)*G([M/(p_t^e)],t+1)+\phi(p_t^{(e+1)})]$

建模必備遺傳演算法應用舉例(簡單的一元函式優化例項)

如果喜歡這裡的內容,你能夠給我最大的幫助就是轉發,告訴你的朋友,鼓勵他們一起來學習。 If you like the content here, you can give me the greatest help is forwarding, tell you

ADO.NET1、簡單配置與使用

字符串 文件中 .exe 增加 獲取字符串 pass 數據庫連接 rect manage 1、一些基礎的知識點 ExecuteReader(); //返回查詢到的數據,一次一行,用於 selectExecuteNonQuery(); //返回影響的行數,用於 delete,

數論線性洛谷P1865 A%B problem

continue 個數 區間 str 輸出 數據 兩個 裸題 n) 題目背景 題目名稱是吸引你點進來的 實際上該題還是很水的 題目描述 區間質數個數 輸入輸出格式 輸入格式: 一行兩個整數 詢問次數n,範圍m 接下來n行,每行兩個整數 l,r 表示區間 輸出格式:

設計模式簡單工廠模式和工廠方法模式

產生 for plm nbsp osc rbm play stp mage > 簡單工廠模式 顧名思義,此模式的設計結構是簡單的,核心是生產對象。 一般來說,運用工廠模式生產的對象應該是構建對象的過程比較復雜的,獲取構建對象的過程在日後可能發生變更的。 簡單工廠

JS+CSS簡單實現DIV遮罩層顯示隱藏轉藏

button left dtd -m javascrip htm width dex absolute <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/

HDU1237 簡單計算器 +逆波蘭式

a + b gree rac 簡單計算器 data- 3.0 center 一個空格 har 簡單計算器 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe