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;

}
上一篇:linux:mysql数据库备份


下一篇:1033 旧键盘打字 (20 分)