有的時候,我們需要求一些積性函式的字首和,而且需要在低於線性時間複雜度內完成,這時就可以用到杜教篩啦
其實不是積性函式也可以但是要可以在接近線性的時間內求出來
假設我們要求積性函式f(n)的字首和 $s(n)=\sum_^\ f(n)$
如果n夠小我們可以考慮線性篩,但當n的範圍為1e9呢
溫納圖萬教篩就光榮登場了
我們考慮在找到乙個積性函式g
把f*g的字首和算出來有 $ \sum _^(f*g)(i)= \sum _^ \sum_\ f(\frac)g(d) $
可以發現這個式子等於 $ \sum_^ g(d)s(\left \lfloor \frac \right \rfloor) $
其實上面的看不懂無所謂
其實只需要記住把我們要求的式子提出後的式子
即提出g(1)s(n)
此時有 $ g(1)s(n)= \sum _^(f*g)(i) - \sum_^ g(d)s(\left \lfloor \frac \right \rfloor) $
當 $ m=n^} $ 時最優 複雜度為 o($n^} $)
當然如果是多組資料還是能多處理就多處理吧
一般情況下會用到的輔助的積性函式
1. g(n)=1
2.g(n) = n
求 $ \sum _^ \mu(i) $
構造g(n) = 1, 設f*g=h
有h(n)=[n=1]
故 s(n) = $ \sum _^(f*g)(i) - \sum_^ s(\left \lfloor \frac \right \rfloor) $
顯然 $ \sum _^(f*g)(i) $ =1
故s(n) =$ 1 - \sum_^ s(\left \lfloor \frac \right \rfloor) $
整除分塊+記憶化搜尋即可
**是洛谷模板的**多了乙個求尤拉函式的**
#includeusingnamespace
std;
#define r register
const
int maxn = 7000000 + 10
;inline
intread()
while(ch<'
0'||ch>'9'
);
dowhile(ch>='
0'&&ch<='9'
);
return f*x;
} long
long
t;int
n;unsigned
long
long
phi[maxn];
intmu[maxn];
intprime[maxn],prime_cnt;
bool
notprime[maxn];
maplong ,long
long >w2;
maplong
long ,long
long >w1;
inline
void
init()
for(r int j=1;j<=prime_cnt;j++)
notprime[i*prime[j]] = 1
;
if(i%prime[j]==0
)
else}}
for(r int i=2;i<=maxn;i++) mu[i]+=mu[i-1
];
for(r int i=2;i<=maxn;i++) phi[i]+=phi[i-1];}
inline unsigned
long
long djs_phi(long
long
x)
return w1[x]=sum;
}inline
long
long djs_mu(long
long
x)
return w2[x]=sum;
}int
main()
}
習題 杜教篩(Sum)(杜教篩)
傳送門杜教篩的板子,拿來練手 beginans sum phi i end g n 1,phi n f n h n sum phi d g frac n h n sum f d g frac 令f n sum f i h n sum h i beginh n sum h i sum sum f d ...
BZOJ P3944 Sum 數論 杜教篩
bzoj傳送門 一共t 1行 第1行為資料組數t t 10 第2 t 1行每行乙個正整數n,代表一組詢問 output 一共t行,每行兩個用空格分隔的數ans1,ans2 sample input 6 1 2 8 13 30 2333 sample output 1 1 2 0 22 2 58 3 ...
模板 杜教篩
杜教篩用來解決積性函式求字首和的問題。複雜度為 o n frac 適用情況 已知函式 f 求 sum f 存在 f g f 且 g,sum g,f,sum f 容易求出。常用公式 mu i n 1 varphi i id 以求 sum mu 為例。mu i n 1 sum i 1 1 1 sum i...