1. 程式人生 > 其它 >P4562 [JXOI2018]遊戲

P4562 [JXOI2018]遊戲

給定一個區間[L,R],每次可以去除區間一個數字及其它的倍數,求把整個區間消去的步數的所有情況的和

我們可以定義整個區間偽素數為這個區間沒有它的倍數的數,那麼一個消去順序的步數就是最後面的偽素數。那麼我們可以列舉這個最右邊的偽素數的質數的位置為i,依次算出每個位置的貢獻,方案數
設偽素數的個數為sum,區間長度為n
那麼總答案為

\[\sum_{sum}^{n} i(步數)*sum(最右邊偽素數的種類)* \\ \binom{n-sum}{n-i}(最右邊偽素數的右邊非偽素數的方案) \\ * (n-i)(右邊數字的全排列)! *(i-1) ! \]

求偽素數的方法可以用埃氏篩
時間複雜度\(O(n \ log \ log \ n)\)

lxl inv_fac[N], fac[N];
lxl len, sum, ans, temp;
bool v[N];
inline void init() {
	fac[0] = 1;
	rep(i, 1, len) {
		fac[i] = fac[i - 1] * i % mod;
	}

	inv_fac[len] = Quick_Pow(fac[len], mod - 2);
	drp(i, len - 1, 0) {
		inv_fac[i] = inv_fac[i + 1] * (i + 1) % mod;
	}


	rep(i, L, R) {
		if(v[i]) continue;
		++sum;
		for(int j(i << 1); j <= R; j += i) {
			v[j] = 1;
		}
	}
}

inline lxl C(int n, int m) {
	if(n < m) {
		return 0;
	}
	return fac[n] * inv_fac[m] % mod * inv_fac[n - m] % mod;
}

int main() {
	read(L);
	read(R);
	len = R - L + 1;

	init();

	rep(i, sum, len) {
		
		temp = 1ll * i * sum % mod;
		temp = temp * C(len - sum, len - i) % mod;
		temp = temp * fac[len - i] % mod * fac[i - 1] % mod;
		ans = (ans + temp) % mod;
	}
	out(ans, '\n');
	return 0;

}

本文來自部落格園,作者:{2519},轉載請註明原文連結:https://www.cnblogs.com/QQ2519/p/15500627.html