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;
}

猜你喜欢

转载自www.cnblogs.com/psimonw/p/11626387.html