BZOJ3930 選數(莫比烏斯反演,杜教篩)

2021-08-14 17:32:54 字數 2215 閱讀 9398

給定n,

k,l,

r 問從l

~r中選出

n 個數,使得他們gc

d=k的方案數

這樣想,既然gc

d=k ,首先就把區間縮小一下

這樣變成了gc

d=1

設f(i

) 表示gc

d 恰好為

i 的方案數

那麼,要求的是f(

1)設g

(x)=

∑d|x

f(d)

所以g(

x)表示x|

gcd 的方案數

這個不是很好求嗎?

所以一波莫比烏斯反演 f(

1)=∑

i=1μ

(i)g

(i)

好的,看看g(

x)怎麼直接求

現在可以取的區間範圍是l~

r 要讓g

cd是x

的倍數

區間的大小算一下,直接快速冪就行了

然後80

分到手啦

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define mod 1000000007

#define max 10000000

inline

int read()

int n,k,l,r;

bool zs[max];

int pri[max+1],tot,mu[max+1];

void pre()

}}int fpow(int a,int b)

return s;

}int g(int x,int l,int r)

int main()

現在的問題是l,

r 範圍很大

但是我們又要求乙個大的μ

怎麼辦嗷。。

非線性時間誒。

杜教篩??

我們可以搞一下

μ 的字首和就行了,

這樣兩個相減就是μ

設s(n

)=∑n

i=1μ

(i)

g(1)

s(n)

=∑i=

1n(g

∗μ)(

i)−∑

i=2n

g(i)

s(ni

) 取g

(x)=

1 s(

n)=1

−∑i=

2ns(

ni)

現在可以算出

μ 啦

再回去看一下上面寫的**

發現可以數論分塊

於是再來一次數論分塊

這題就沒啦

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define mod 1000000007

#define max 10000000

inline

int read()

int n,k,l,r;

bool zs[max];

int pri[max+1],tot,mu[max+1],smu[max+1];

map m;

void pre()

}for(int i=1;i<=max;++i)smu[i]=smu[i-1]+mu[i];

}int fpow(int a,int b)

return s;

}int smu(int x)

return m[x]=ret;

}int main()

printf("%d\n",(ans+mod)%mod);

return

0;}

bzoj3930 選數 遞推

看了一下popoqqq爺的莫比烏斯反演,果斷棄療。還是寫遞推好,又短又快。令f i 表示當數不全相等時 為什麼如此,後面再說 最小公倍數為i k的方案,那麼 首先,當公倍數 注意不是最小 為i k時,總方案數x n x,其中x表示l r中i k的倍數,再減去重複的方案 u 2,i k u r l f...

bzoj3930 數論 選數

description 我們知道,從區間 l,h l和h為整數 中選取n個整數,總共有 h l 1 n種方案。小z很好奇這樣選出的數的最大公約數的規律,他決定對每種方案選出的n個整數都求一次最大公約數,以便進一步研究。然而他很快發現工作量太大了,於是向你尋求幫助。你的任務很簡單,小z會告訴你乙個整數...

BZOJ 2301 莫比烏斯

比較裸的一道莫比烏斯入門題 具體題解網上多的是 比較簡單 不知道為什麼別人 都那麼長 沒有我的優雅哈哈哈 這題不要列舉 要分塊處理 ac includeusing namespace std typedef long long ll const ll n 1e6 ll miu n 10 v n 10...