PE做题记录

675

只要猜出\(S(n)\)是个积性函数就好。
正确性显然。
\((n, m) = 1\)

\[\begin{aligned} S(nm) & = \sum_{d | nm} 2 ^ {\omega (d)} \\ & = \sum_{d_1 | n} \sum_{d_2 | m} 2 ^ {\omega (d_1 d_2)} \\ & = \sum_{d_1 | n} \sum_{d_2 | m} 2 ^ {\omega (d_1) + \omega (d_2)} \\ & = \sum_{d_1 | n} 2 ^ {\omega (d_1)} \sum_{d_2 | m} 2 ^ {\omega (d_2)} \\ & = S(n) \cdot S(m) \end{aligned} \]

其中,因为\((n, m) = 1\)\((d_1, d_2) = 1\),有\(\omega(d_1) + \omega(d_2) = \omega(d_1 d_2)\)
现在我们知道\(S\)是积性函数,但不是完全积性,但这足够了。
简单计算可以知道

\[S(n) = \begin{cases} 1, & n = 1 \\ 2k + 1, & n = p ^ k, p \in \mathbb {P} \\ \end{cases} \]

这样,如果\(n = p_1 ^ {x_1} p_2 ^ {x_2} \ldots p_k ^ {x_k}\),则

\[S(n) = \prod_{i = 1} ^ k (2x_i + 1) \]

由于要求

\[\sum_{i = 2} ^ n S(i!) \]

考虑每次从\(S(i!)\)推向\(S((i+1)!)\),多了一个\(i\),对其中一些素数的个数产生了贡献。
直接把影响到的素因子的个数修改,以及对答案进行修改即可。
注意要线性求逆元。
复杂度\(\mathcal O(n \log \log n)\)
其中有一些小细节,具体见代码。

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
const int N = 1e7 + 5, mod = 1e9 + 87;
int n, las, ans, inv[N << 1], cnt[N]; bool vis[N];
vector <pii> pf[N];
int power (int a, int b) {
	int ret = 1;
	for ( ; b; b >>= 1, a = 1ll * a * a % mod) {
		if (b & 1) {
			ret = 1ll * ret * a % mod;
		}
	}
	return ret;
}
int main () {
	scanf("%d", &n);
	inv[1] = 1;
	for (int i = 2; i <= n * 2; ++i) {
		inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;
	}
	for (int i = 2; i <= n; ++i) {
		if (!vis[i]) {
			pf[i].push_back(mp(i, 1));
			for (int j = i + i, k; j <= n; j += i) {
				vis[j] = 1;
				if (j / i % i == 0) {
					k = pf[j].size();
					pf[j].push_back(mp(i, 1 + pf[j / i][k].se));
				} else{
					pf[j].push_back(mp(i, 1));
				}
			}
		}
	}
	las = 1, ans = 0;
	for (int i = 2; i <= n; ++i) {
		for (auto x : pf[i]) {
			las = 1ll * las * inv[cnt[x.fi] * 2 + 1] % mod;
			cnt[x.fi] += x.se;
			las = 1ll * las * (cnt[x.fi] * 2 + 1) % mod;
		}
		ans = (ans + las) % mod;
	}
	printf("%d\n", ans);
	return 0;
}

605

低难度续命题。被续惨了。
\(p(n, k)\)\(n\)个人的游戏,第一个人输了round 1,第\(k\)个人最终赢得游戏的概率,\(q(n, k)\)\(n\)个人的游戏,第一个人赢了round 1,第\(k\)个人最终赢得游戏的概率。
则有

\[p(n, k) = (\frac{1}{2}) ^ {k + 1 - 2} + (\frac{1}{2}) ^ {n - 1} \cdot \frac {1}{2} \cdot p(n, k) \\ q(n, k) = (\frac{1}{2}) ^ 2 \cdot \frac{k - 1 - 2 + 1}{2 ^ {k - 1 - 2}} + (\frac{1}{2}) ^ {n - 1} \cdot \frac {1}{2} \cdot q(n, k) + (\frac{1}{2}) ^ {n - 1} \cdot n \cdot \frac{1}{2} \cdot p(n, k) \\ ans = \frac{1}{2} (p(n, k) + q(n, k)) \]

解得

\[ans = \frac{2 ^ {n - k} (n + (k - 1)(2 ^ n - 1))}{(n - 1) ^ 2} \]

但是题目很毒瘤,要求把概率约成最简后输出分子乘分母的乘积。
只是因为这题数据给得好,\(n = {10} ^ 8 + 7, k = {10} ^ 4 + 7\),分子和分母\(\gcd\)刚好为1。
其实也是可以粗略证明的。
\(g = (numerator, denominator)\),则因为\((2 ^ n - 1, 2 ^ {n - k}) = 1\),所以\(g = (n + (k - 1)(2 ^ n - 1), (2 ^ n - 1) ^ 2)\)
我们假设\(g > 1\),那么应当有\((n + (k - 1)(2 ^ n - 1), 2 ^ n - 1) > 1\)
根据辗转相除,又有\((n, 2 ^ n - 1) > 1\),但是实际上\((n, 2 ^ n - 1) = 1\)(这个等式不成立的概率很小,何况\(n\)还是一个大素数),所以假设不成立。
所以\(g = 1\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9;
int n, k, num, den;
int power (int a, int b) {
	int ret = 1;
	for ( ; b; b >>= 1, a = 1ll * a * a % mod) {
		if (b & 1) {
			ret = 1ll * ret * a % mod;
		}
	}
	return ret;
}
int main () {
	n = 1e8 + 7, k = 1e4 + 7;
	num = 1ll * power(2, n - k) * (1ll * (power(2, n) - 1) * (k - 1) % mod + n) % mod;
	den = power(power(2, n) - 1, 2);
	cout << 1ll * num * den % mod << endl;
	return 0;
}

607

这道题的模型其实就是光的折射,或者说是费马原理。
把它类比为光的折射,根据斯涅尔定理,设入射角为\(\theta_1\),折射角为\(\theta_2\),入射速度为\(v_1\),出射速度为\(v_2\),有

\[\frac{\sin \theta_1}{v_1} = \frac{\sin \theta_2}{v_2} \]

则可以考虑二分第一个入射角,然后判断平行于沼泽岸的距离是否等于垂直于沼泽岸的距离(\(50 \sqrt 2\))。

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0), ht = 100.0 / sqrt(2.0), d = 50.0 / sqrt(2.0) - 25.0, rec = pi / 2;
double the[10], l, r, mid, len, t;
int main () {
	memset(the, 0, sizeof the);
	l = 0, r = rec;
	while (r - l >= 1e-12) {
		mid = (l + r) / 2, len = 0, t = 0;
		the[0] = mid, len += d / tan(the[0]), t += d / sin(the[0]) / 10.0;
		the[1] = rec - asin(sin(rec - the[0]) / 10 * 9), len += 10.0 / tan(the[1]), t += 10.0 / sin(the[1]) / 9.0;
		the[2] = rec - asin(sin(rec - the[1]) / 9 * 8), len += 10.0 / tan(the[2]), t += 10.0 / sin(the[2]) / 8.0;
		the[3] = rec - asin(sin(rec - the[2]) / 8 * 7), len += 10.0 / tan(the[3]), t += 10.0 / sin(the[3]) / 7.0;
		the[4] = rec - asin(sin(rec - the[3]) / 7 * 6), len += 10.0 / tan(the[4]), t += 10.0 / sin(the[4]) / 6.0;
		the[5] = rec - asin(sin(rec - the[4]) / 6 * 5), len += 10.0 / tan(the[5]), t += 10.0 / sin(the[5]) / 5.0;
		the[6] = rec - asin(sin(rec - the[5]) / 5 * 10), len += d / tan(the[6]), t += d / sin(the[6]) / 10.0;
		if (len > ht) {
			l = mid;
		} else {
			r = mid;
		}
	}
	printf("%.10lf\n", t);
	return 0;
}

330

奇怪的题。
我只能算出\(a(n)\)\(OGF\),即\(\mathcal A(x) = \sum_{n = 0} ^ {+\infty} a(n) x ^ n\)

\[\mathcal A(x) = \frac{e ^ x - x ^ 2 - 1}{(e ^ x - 2)(x ^ 2 - x)} \]

然后用多项式求逆可以求出这个多项式的前若干项。
不过这个模数很特殊,尽管不能做\(NTT\),但是由于\(77777777 = 7 * 11 * 73 * 101 * 137\),我们只要计算出在对几个小模数取模后的答案,用中国剩余定理合并即可。
但是问题是我们要求的是第\({10 ^ 9}\)项。幸运的是,在对这些质数取模的情况下,系数会出现循环节,循环节长度是\(\mathcal O(p ^ 2)\)级别的。
这样我们可以用\(\mathcal O(p ^ 2)\)的复杂度暴力做多项式求逆,然后再计算。
但是题目要求的是令\(a(n) = \frac{A(n) \cdot e + B(n)}{n!}\),这一定得把\(A(n)\)\(B(n)\)拆开算,也就是要考虑\(a(n)\)的递归式的贡献,会复杂些。
这个坑……只能暂时就这样啦……

posted @ 2019-10-06 09:01  psimonw  阅读(136)  评论(0)    收藏  举报